我有List<T1>
个项目和第二个List<T2>
个项目。两个列表都按属性A按字母顺序排序。我知道List<T2>
中的项目列表是List<T1>
的子集,List<T2>
中没有List<T1>
中的项目存在于List<T1>
中不存在1}}。
我需要遍历List<T2>
并在每次匹配{{1}}中的变量时更改变量。什么是最快和最好的方法?我假设我需要遍历两个列表,但我知道做一个嵌套的foreach是没有意义的。
答案 0 :(得分:12)
对于这种类型的东西,我更喜欢双行走循环。请参阅下面的示例。
var super = new List<Contact>();
super.Add(new Contact() {Name = "John"});
super.Add(new Contact() {Name = "Larry"});
super.Add(new Contact() {Name = "Smith"});
super.Add(new Contact() {Name = "Corey"});
var sub = new List<Contact>();
sub.Add(new Contact() {Name = "Larry"});
sub.Add(new Contact() {Name = "Smith"});
var subCount = 0;
for(int i=0; i<super.Count && subCount < sub.Count; i++)
{
if (super[i].Name == sub[subCount].Name)
{
Act(super[i], sub[subCount]);
subCount++;
}
}
Act(...)
执行您要执行的任何操作。
循环每次都会递增超级列表,但只有在找到匹配项时才会递增子列表。
请注意,这仅适用于您的两个假设。 1)列表都是排序的,2)第二个列表是第一个列表。
答案 1 :(得分:5)
如果列表不是太大,最简单的方法是拨打Contains
:
foreach(var item in list1) {
if (list2.Contains(item) {
//Do something
}
}
您可以使用自定义BinarySearch
致电IComparer<T>
来加快速度,例如:
class MyComparer : IComparer<YourClass> {
private MyComparer() { }
public static readonly MyComparer Instance = new MyComparer();
public int CompareTo(YourClass a, YourClass b) {
//TODO: Handle nulls
return a.SomeProperty.CompareTo(b.SomeProperty);
}
}
foreach(var item in list1) {
if (list2.BinarySearch(item, MyComparer.Instance) >= 0) {
//Do something
}
}
在.Net 3.5中,您可以使用HashSet<T>
:
var hashset = new HashSet<YourClass>(list2);
foreach(var item in list1) {
if (hashset.Contains(item) {
//Do something
}
}
如果您的列表非常大,您应该衡量每个选项的效果并相应地选择 否则,请选择最简单的第一个选项之一。
答案 2 :(得分:1)
如果它们都在唯一属性上排序,则可以在迭代期间使用它。我们的想法是遍历超集,然后根据排序的唯一属性推进子集迭代器,直到它匹配或者比超集更大/更小(取决于排序顺序)。
对于按升序排序的属性:
if (subsetList.Count > 0)
{
using(IEnumerator<T2> subset = subsetList.GetEnumerator())
{
subset.MoveNext();
T2 subitem = subsetList.Current;
foreach(T1 item in supersetList)
{
while (item.A > subitem.A &&
subset.MoveNext())
{
subitem = subset.Current;
}
if (item.A == subitem.A)
{
// Modify item here.
}
}
}
}
请注意,这实际上并不依赖于supersetList
是subsetList
的超集。 EndangeredMassa的解决方案更清晰,假设是真的。
答案 3 :(得分:1)
您的问题意味着您希望每次都避免迭代第二个列表中的所有项目,这是使用Contains()
在最坏情况下的天真解决方案中会发生的情况。由于两个列表都已排序且list2
是list1
的子集,因此您知道list1
中的任何条目的索引都不会小于list2
中的相应条目。考虑到这一点,您可以使用两个枚举器制作有效的O(n)解决方案:
Debug.Assert(list1.Count > 0);
Debug.Assert(list1.Count >= list2.Count);
var enum1 = list1.GetEnumerator();
var enum2 = list2.GetEnumerator();
enum1.MoveNext();
while (enum2.MoveNext())
{
// Skip elements from list1 that aren't equal to the current entry in list2
while (!enum1.Current.Equals(enum2.Current))
enum1.MoveNext();
// Fire the OnEqual event for every entry in list1 that's equal to an entry
// in list2
do {
OnEqual(enum1.Current, enum2.Current);
} while (enum1.MoveNext() && enum1.Current.Equals(enum2.Current));
}
enum1.Dispose();
enum2.Dispose();