2010-04-23 42 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

相关问题