LINQ查询将列表中的少数项目视为已选中

时间:2011-07-30 14:47:21

标签: c# .net linq

这是该计划以及评论。我有一个ListA和ListB。我想将ListA的IsChecked = true,如果它存在于ListB中。这是该计划:

public class SomeClass
{
    public bool IsChecked { get; set; }
    public string Title { get; set; }
}

List<SomeClass> ListA = new List<SomeClass>
{
    new SomeClass { IsChecked = false, Title = "A" },
    new SomeClass { IsChecked = false, Title = "B" },
    new SomeClass { IsChecked = false, Title = "C" },
    new SomeClass { IsChecked = false, Title = "D" },
    new SomeClass { IsChecked = false, Title = "E" },
    new SomeClass { IsChecked = false, Title = "F" },
};

List<SomeClass> ListB = new List<SomeClass>
{
    new SomeClass { Title = "A" },
    new SomeClass { Title = "D" },
    new SomeClass { Title = "F" },
};

// some linq query at the end of which listA's Item containing Title = "A","D","F" will become true

foreach (var item in ListA)
{
    Console.WriteLine(item.Title + " " + item.IsChecked); 
}
Console.ReadKey();

这就是我提出的:

foreach (var item in ListB)
{
    var listAItem = (from itemA in ListA
                     where itemA.Title == item.Title
                     select itemA).First(); //no need for FirstOrDefault() because it is always going to be present

    listAItem.IsChecked = true;
}

但这看起来非常低效。使用Linq有没有更好的方法呢?我只想在LINQ中使用解决方案。

5 个答案:

答案 0 :(得分:5)

你可以像这样使用Join

var itemAsToBeChecked = from itemA in ListA 
                        join itemB in ListB on itemA.Title equals itemB.Title 
                        select itemA;

foreach (var itemA in itemAsToBeChecked)
    itemA.IsChecked = true;

相信 Microsoft的Join实现将首先在Lookup<,>上从TitleSomeClass创建查找(ListB)在枚举ListA之前,将每个itemA与查找匹配。这应该比您目前的解决方案更有效。

如果您愿意,也可以考虑使用HashSet<T>

var titlesToBeChecked = new HashSet<string>(ListB.Select(itemB => itemB.Title));
var itemAsToBeChecked = ListA.Where(itemA => titlesToBeChecked.Contains(itemA.Title));

foreach (var itemA in itemAsToBeChecked)
    itemA.IsChecked = true;

当然,像其他人提到的那样,在你的类型上实现IEqualityComparer<T>可能是有意义的,特别是如果你的程序中经常使用基于Title的相等定义。

答案 1 :(得分:2)

你可以做到

foreach(var item in ListA.Where( x => ListB.Contains(x)))
  item.IsChecked = true;

这需要您的班级SomeClass实施IEquatable<SomeClass>来比较Title属性:

public class SomeClass : IEquatable<SomeClass>
{
    public bool IsChecked { get; set; }
    public string Title { get; set; }

    public bool Equals(SomeClass other)
    {
       return this.Title == other.Title;
    }
}

或者,您可以使用Intersect(),这需要您提供IEqualityComparer

foreach (var item in ListA.Intersect(ListB, new SomeClassComparer()))
    item.IsChecked = true;

...
public class SomeClassComparer : IEqualityComparer<SomeClass>
{
    public bool Equals(SomeClass x, SomeClass y)
    {
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
             return false;
        return x.Title == y.Title;
    }

    public int GetHashCode(SomeClass obj)
    {
        return obj.Title.GetHashCode();
    }
}

答案 2 :(得分:1)

一种解决方案(如果您无法控制该类,则不需要实施IComparableIEquatable):

foreach (var item in ListA.Where(a => ListB.Any(b => b.Title == a.Title)))
{
    item.IsChecked = true;
}

请记住,除非您想重写ListA,否则您需要此foreach。 Linq是一种查询语言,不应该用于修改现有列表。使用纯Linq隐藏你的意图。可能有一种方法可以适当地使用.Join.Zip来返回新的ListA,但使用传统结构进行修改总是更好。

答案 3 :(得分:1)

var q = from i1 in listA
        from i2 in listB
        where i1.Title == it2.Title
        select i1;

foreach (var i in q)
{
    i.IsChecked = true;
}

答案 4 :(得分:1)

我使用Enumerable.Intersect运算符:

public class SomeClass : IEquatable<SomeClass>
{
    public bool IsChecked { get; set; }
    public string Title { get; set; }

    public bool Equals(SomeClass other)
    {
        //Check whether the compared object is null.
        if (ReferenceEquals(other, null)) return false;

        //Check whether the compared object references the same data.
        if (ReferenceEquals(this, other)) return true;

        //Check whether SomeClass's properties are equal.
        return Title.Equals(other.Title);
    }

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects.
    public override int GetHashCode()
    {
        //Get hash code for the Title field if it is not null.
        int hashSomeClassTitle = Title == null ? 0 : Title.GetHashCode();

        //Calculate the hash code for SomeClass.
        return hashSomeClassTitle;
    }
}

在实施EqualsGetHashCode之后,你很高兴:

var intersection = ListA.Intersect(ListB);

foreach (var item in intersection)
{
    item.IsChecked = true;

    Console.WriteLine(item.Title + " " + item.IsChecked);
}