迭代2个列表

时间:2010-07-20 17:11:34

标签: c# .net .net-3.5 c#-3.0

我有List<T1>个项目和第二个List<T2>个项目。两个列表都按属性A按字母顺序排序。我知道List<T2>中的项目列表是List<T1>的子集,List<T2>中没有List<T1>中的项目存在于List<T1>中不存在1}}。

我需要遍历List<T2>并在每次匹配{{1}}中的变量时更改变量。什么是最快和最好的方法?我假设我需要遍历两个列表,但我知道做一个嵌套的foreach是没有意义的。

4 个答案:

答案 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.
            }
        }
    }
}

请注意,这实际上并不依赖于supersetListsubsetList的超集。 EndangeredMassa的解决方案更清晰,假设是真的。

答案 3 :(得分:1)

您的问题意味着您希望每次都避免迭代第二个列表中的所有项目,这是使用Contains()在最坏情况下的天真解决方案中会发生的情况。由于两个列表都已排序且list2list1的子集,因此您知道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();