这是该计划以及评论。我有一个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中使用解决方案。
答案 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<,>
上从Title
到SomeClass
创建查找(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)
一种解决方案(如果您无法控制该类,则不需要实施IComparable
或IEquatable
):
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;
}
}
在实施Equals
和GetHashCode
之后,你很高兴:
var intersection = ListA.Intersect(ListB);
foreach (var item in intersection)
{
item.IsChecked = true;
Console.WriteLine(item.Title + " " + item.IsChecked);
}