代码之家  ›  专栏  ›  技术社区  ›  Ben Hoffman

遍历2个列表

  •  5
  • Ben Hoffman  · 技术社区  · 14 年前

    我有一个 List<T1> 一个项目和一秒钟 List<T2> 列表<T2> 列表<T1> 中没有项目 列表<T2> 存在于不存在于 列表<T1> .

    我需要重复一遍 列表<T1> . 最快最好的方法是什么?我假设我需要遍历这两个列表,但我知道使用嵌套foreach是没有意义的。

    4 回复  |  直到 14 年前
        1
  •  12
  •   EndangeredMassa    14 年前

    对于这种类型的东西,我更喜欢双环走。请参见下面的示例。

    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)第二个列表是第一个列表的子集。

        2
  •  5
  •   SLaks    14 年前

    如果列表不是太大,最简单的方法就是调用 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
        }
    }
    

    在.NET3.5中,可以使用 HashSet<T> :

    var hashset = new HashSet<YourClass>(list2);
    foreach(var item in list1) {
        if (hashset.Contains(item) {
            //Do something
        }
    }
    

    如果您的列表非常大,您应该衡量每个选项的性能并相应地进行选择。

        3
  •  1
  •   JSBÕ±Õ¸Õ£Õ¹    14 年前

    您的问题意味着您希望避免每次都要迭代第二个列表中的所有项,这在使用 Contains() . 因为两个列表都是排序和 list2 是的子集 list1 ,你知道没有人进入 列表1 索引将小于中的相应条目 . 考虑到这一点,您可以使用两个枚举数生成一个有效的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();
    
        4
  •  1
  •   Community CDub    7 年前

    如果它们都是按唯一属性排序的,则可以在迭代过程中使用该属性。其思想是循环遍历超集,然后根据排序的唯一属性推进子集迭代器,直到它匹配或比超集迭代器大/小(取决于排序顺序)。

    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