代码之家  ›  专栏  ›  技术社区  ›  Bryce Wagner

.NET是否具有用于多个集合的内置IEnumerable?

  •  8
  • Bryce Wagner  · 技术社区  · 14 年前

    我需要一种简单的方法来迭代多个集合而不实际合并它们,而且我找不到任何内置在.NET中的看起来像这样的东西。感觉这应该是一种比较常见的情况。我不想重新发明轮子。有什么内置的东西可以这样做吗?

    public class MultiCollectionEnumerable<T> : IEnumerable<T>
    {
        private MultiCollectionEnumerator<T> enumerator;
        public MultiCollectionEnumerable(params IEnumerable<T>[] collections)
        {
            enumerator = new MultiCollectionEnumerator<T>(collections);
        }
    
        public IEnumerator<T> GetEnumerator()
        {
            enumerator.Reset();
            return enumerator;
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            enumerator.Reset();
            return enumerator;
        }
    
    
        private class MultiCollectionEnumerator<T> : IEnumerator<T>
        {
            private IEnumerable<T>[] collections;
            private int currentIndex;
            private IEnumerator<T> currentEnumerator;
    
            public MultiCollectionEnumerator(IEnumerable<T>[] collections)
            {
                this.collections = collections;
                this.currentIndex = -1;
            }
    
            public T Current
            {
                get
                {
                    if (currentEnumerator != null)
                        return currentEnumerator.Current;
                    else
                        return default(T);
                }
            }
    
            public void Dispose()
            {
                if (currentEnumerator != null)
                    currentEnumerator.Dispose();
            }
    
            object IEnumerator.Current
            {
                get
                {
                    return Current;
                }
            }
    
            public bool MoveNext()
            {
                if (currentIndex >= collections.Length)
                    return false;
                if (currentIndex < 0)
                {
                    currentIndex = 0;
                    if (collections.Length > 0)
                        currentEnumerator = collections[0].GetEnumerator();
                    else
                        return false;
                }
                while (!currentEnumerator.MoveNext())
                {
                    currentEnumerator.Dispose();
                    currentEnumerator = null;
    
                    currentIndex++;
                    if (currentIndex >= collections.Length)
                        return false;
                    currentEnumerator = collections[currentIndex].GetEnumerator();
                }
                return true;
            }
    
            public void Reset()
            {
                if (currentEnumerator != null)
                {
                    currentEnumerator.Dispose();
                    currentEnumerator = null;
                }
                this.currentIndex = -1;
            }
        }
    
    }
    
    2 回复  |  直到 14 年前
        1
  •  15
  •   JaredPar    14 年前

    尝试3.5中添加的selectmany扩展方法。

    IEnumerable<IEnumerable<int>> e = ...;
    foreach ( int cur in e.SelectMany(x => x)) {
      Console.WriteLine(cur);
    }
    

    代码 SelectMany(x => x) 具有将集合扁平化为单个集合的效果。这是以一种懒惰的方式完成的,并允许直接向前处理,如上面所示。

    如果您只有C 2.0可用,那么可以使用迭代器来实现相同的结果。

    public static IEnumerable<T> Flatten<T>(IEnumerable<IEnumerable<T>> enumerable) {
      foreach ( var inner in enumerable ) {
        foreach ( var value in inner ) {
          yield return value;
        }
      }
    }
    
        2
  •  10
  •   EMP    14 年前

    只使用 Enumerable.Concat() “concatenate”两个IEnumerable的扩展方法。不用担心,它实际上不会将它们复制到一个数组中(正如您可能从名称中推断的那样),它只允许您枚举它们,就像它们是一个IEnumerable一样。

    如果你有两个以上那么 Enumerable.SelectMany() 会更好。