如果Contains返回true,则提取列表中的项目

时间:2010-04-23 06:05:05

标签: c# list contains

我有两个列表A和B,在我的程序开头,它们都填充了数据库中的信息(列表A =列表B)。我的程序运行,使用和修改列表A,列表B保持不变。过了一会儿,我用数据库中的新信息重新加载列表B,然后对列表A进行检查。

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

首先,对象播放器是从类创建的,其主要标识符是player.Name。 如果名称相同,但其他变量不同,.Contains是否仍会返回true?

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

在----我需要使用ListB中导致.Contains返回true的项目,我该怎么做?

5 个答案:

答案 0 :(得分:5)

List.Contains的默认行为是它使用默认的相等比较器。如果您的商品是引用类型,则表示它将使用身份比较,除非您的类通过Equals提供其他实现。

如果您使用的是.NET 3.5,那么您可以将第二行更改为可以执行所需的操作:

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

对于.NET 2.0,您可以为您的类实现EqualsGetHashCode,但是如果您不希望两个播放器对象相等,则可能会产生不良行为同名,但在其他领域有所不同。

另一种方法是使Jon Skeet's answer适用于.NET 2.0。创建一个Dictionary<string, object>并在其中填入listB中所有玩家的名字。然后,为了测试具有特定名称的玩家是否在listB中,您可以使用dict.ContainsKey(name)

答案 1 :(得分:2)

Mark的建议的另一种选择是构建一组名称并使用它:

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

答案 2 :(得分:0)

假设您使用的是System.Collections.Generic.List类,如果CPlayer类没有实现IEquatable<T>,它将使用EqualsGetHashCode函数{ {1}}类来检查CPlayer是否有一个等于List参数的成员。假设您的实现没问题,您可以使用

Contains

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

获取实例

答案 3 :(得分: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);
}

答案 4 :(得分:0)

如果你想让.Contains方法只匹配CPlayer.Name,那么在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比较为Case Insensitive,请替换使用此Equals方法:

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

如果您这样做,您的.Contains调用将按您的意愿运行。 其次,如果要在列表中选择此项,请执行以下操作:

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

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

<强> UPD: 这可能是一个主观陈述,但如果你的.Equals方法在进行字符串比较之前比较Int哈希值,你也可以从中挤出一些性能。

查看.NET源代码(Reflector FTW)我可以看到,似乎只有HastTable类使用GetHashCode来提高它的性能,而不是每次使用.Equals来比较对象。在像这样的小类的情况下,相等比较器很简单,单个字符串比较..如果你比较所有属性,那么比较两个整数会快得多(特别是如果它们被缓存:))

List.Contains和List.IndexOf不使用哈希码,并使用.Equals方法,因此我建议检查里面的哈希码。它可能不会引起任何注意,但是当你渴望获得每一个ms的执行时(并不总是一件好事,bug嘿!:P)这可能对某人有所帮助。只是说......:)