2010-04-23 63 views
1

我有兩個列表A和B,在我的程序開始時,它們都充滿了來自數據庫(List A = List B)的信息。我的程序運行,列表A被使用和修改,列表B被單獨留下。過了一會兒,我重新加載列表B與數據庫中的新信息,然後做一次檢查與打擊名單A.如果Contains返回true,則在列表中提取項目

foreach (CPlayer player in ListA) 
     if (ListB.Contains(player)) 
      ----- 

首先,從類創建的對象播放器,它的主要標識是player.Name 。 如果名稱相同,但其他變量不同,.Contains仍會返回true嗎?

Class CPlayer(
     public CPlayer (string name) 
       _Name = name 

在----我需要使用從數組listB引起。載有返回true的項目,我該怎麼做呢?

回答

5

默認行爲List.Contains是它使用默認的相等比較器。如果您的項目是引用類型,這意味着它將使用身份比較,除非您的課程通過Equals提供了另一個實施。

如果您使用的是.NET 3.5,那麼你可以在你的第二行改成這樣,將你想要做什麼:

if (ListB.Any(x => x.Name == player.Name)) 

對於.NET 2.0,你可以實現你的類EqualsGetHashCode,但這在其他情況下可能會產生不良行爲,在這種情況下,如果兩個播放器對象的名稱相同但其他字段不同,則不希望兩個播放器對象進行比較。

另一種方法是適應.NET 2.0的Jon Skeet's answer。創建一個Dictionary<string, object>並用列表B中的所有玩家的名字填充它。然後爲了測試某個名字的玩家是否在listB中,你可以使用dict.ContainsKey(name)

+0

.NET 2.0不幸的是 – Matt 2010-04-23 08:37:54

+0

@Matt:現在增加了.NET 2.0的可能解決方案。 – 2010-04-23 09:06:31

2

馬克的建議,另一種方法是建立一組名稱和使用:

HashSet<string> namesB = new HashSet<string>(ListB.Select(x => x.Name)); 
foreach (CPlayer player in ListA) 
{ 
    if (namesB.Contains(player.Name)) 
    { 
     ... 
    } 
} 
0

假設你正在使用的System.Collections.Generic.List類,如果CPlayer類不實現IEquatable<T>它將使用EqualsGetHashCodeCPlayer類的函數來檢查List是否有等於Contains的參數的成員。假設實現是你行,你可以像

CPlayer listBItem = ListB.First(p => p == player);

ListB

0

這聽起來像這樣得到的實例是,你需要完成的任務:

對於每個玩家在列表A中,找到列表B中每個具有相同名稱的玩家,並將兩個玩家放在同一個範圍內。

這裏是連接兩個列表中查詢的方法:

var playerPairs = 
    from playerA in ListA 
    join playerB in ListB on playerA.Name equals playerB.Name 
    select new { playerA, playerB }; 

foreach(var playerPair in playerPairs) 
{ 
    Console.Write(playerPair.playerA.Name); 
    Console.Write(" -> "); 
    Console.WriteLine(playerPair.playerB.Name); 
} 
0

如果您希望。載的方法來匹配就CPlayer。名稱,然後在CPlayer類實現這些方法:

public override bool Equals(object obj) 
{ 
    if (!(obj is CPlayer) 
     return false; 
    return Name == (obj as CPlayer).Name; 
} 
public override int GetHashCode() 
{ 
    return Name.GetHashCode(); 
} 

如果你想Name比較是不區分大小寫,代替使用此equals方法代替:

public override bool Equals(object obj) 
{ 
    if (!(obj is CPlayer) 
     return false; 
    return Name.Equals((obj as CPlayer).Name, StringComparison.OrdinalIgnoreCase); 
} 

如果你這樣做,你的。包含呼叫將按照您的需要進行工作。 其次,如果你想在列表中選擇該項目,這樣做:

var playerB = ListB[ListB.IndexOf(player)]; 

它使用相同.Equals和.GetHashCode方法。

UPD: 這可能是一個主觀的說法,但你也可以擠一些表現出來的是,如果你的.Equals方法相比,詮釋做字符串比較之前散列..

綜觀.NET源代碼(Reflector FTW)我可以看到,似乎只有HastTable類使用GetHashCode來提高它的性能,而不是每次使用.Equals來比較對象。在這樣一個小類的情況下,相等比較器很簡單,比較單個字符串。如果你比較了所有的屬性,那麼比較兩個整數會更快(尤其是如果它們被緩存:))

List.Contains和List.IndexOf不使用哈希碼,並使用.Equals方法,因此我建議檢查裏面的哈希碼。它可能不會引起任何注意,但是當你渴望得到每一個執行的ms(並不總是一件好事,bug hey!:P),這可能會幫助某人。只是說... :)

+0

您能否提供一些證據或理由:「如果在執行字符串比較之前,您的.Equals方法比較了Int哈希值,那麼您還可以從中獲得一些性能。」? – 2010-04-23 08:55:48

+0

在帖子中添加了解釋。這部分是主觀的,但只是部分) – 2010-04-23 09:14:59

相關問題