2010-08-26 22 views
9

给定一个有限的元素列表,我如何创建一个(懒惰评估,感谢LINQ!)无限列表,只是不断迭代我的初始列表?linq无限列表从给定的有限列表

如果最初的名单是{1, 2, 3},我希望新的列表返回{1, 2, 3, 1, 2, 3, 1, ...}

回答

16

yield return是一个相当方便的操作符,虽然它并不真正需要特定的LINQ。

IEnumerable<int> GetInfiniteSeries(IEnumerable<int> items) { 
    while (true) { 
     foreach (var item in items) { 
      yield return item; 
     } 
    } 
} 
+1

比我的版本短很多:) – 2010-08-26 13:59:57

6
IEnumerable<T> Infinite(this IEnumerable<T> ienum) 
{ 
    List<T> list = ienum.ToList(); 
    while (true) 
     foreach(var t in list) 
      yield return t; 
} 



foreach(int i in Enumerable.Range(1,3).Infinite()) 
     Console.WriteLine(i); 
+0

是调用'ToList()'有必要吗? – 2010-08-26 13:55:20

+0

+1: 虽然有两个问题: 1.当无条件()'在逻辑上是'Infinite()'实现应该支持这个时,这不会与'ienum.Infinite()。 2.如果我们忽略了第1点,就会出现性能问题:枚举器不断重新创建和处置。它会更好地被重新定义为一个for循环,当它碰到list.Count时它会重置为0。另一种方法是依靠'IEnumerator.Reset()',但我认为这是很危险的,因为很多实现不支持它。 – Ani 2010-08-26 14:00:14

+2

@Ani:你怎么知道有一个性能问题?你知道吗?没有经验证据表明,创建和销毁列表迭代器是BCL团队专门设计的一个结构,它非常快速地分配和处理 - 是用户应用程序中最慢的东西。还是你做了大量仔细的分析工作,以确定这个结构的分配和处理实际上是用户应用程序中最大的性能问题?如果是这样,那么我希望看到这些数据,以便我可以将它传递给BCL性能团队,谢谢! – 2010-08-26 14:12:20

3

下面是我最终做到了:

public static IEnumerable<T> AdNauseam<T>(this IEnumerable<T> i_list) 
    { 
     using(var etor = i_list.GetEnumerator()) 
     { 
      while(true) 
      { 
       while(etor.MoveNext()) 
       { 
        yield return etor.Current; 
       } 
       etor.Reset(); 
      } 
     } 
    } 

用法:

var list = new[] {1, 2, 3} 
var infinite = list.AdNauseam().Take(10); 

结果:

{1, 2, 3, 1, 2, 3, 1, 2, 3, 1} 
+0

我想知道在这种情况下using()是否有用。 – 2010-08-26 13:52:03

+1

使用()是必要的 - IEnumerator 实现IDisposable。对于大多数列表来说,配置可能没有太大的作用,但是如果枚举器做了一些新颖的事情,比如从文件或数据库中读取数据,你会希望它被丢弃。 – 2010-08-26 14:04:19

+2

我想知道使用重置是最好的选择,因为'重置方法提供了COM互操作性。它不一定需要实施;相反,实现者可以简单地抛出一个NotSupportedException异常。' (来源:http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.reset(v=vs.110)。aspx) – 2014-05-30 10:04:01

2

另一种选择,实现IEnumerator<T>

public class InfiniteEnumerator<T> : IEnumerator<T> 
    { 
     private IList<T> _items; 
     private int _index = -1; 

     public InfiniteEnumerator(IList<T> items) 
     { 
      if (items == null) 
      { 
       throw new ArgumentNullException("items"); 
      } 
      _items = items; 
     } 

     public T Current 
     { 
      get { return _items[_index]; } 
     } 

     public void Dispose() 
     { 

     } 

     object System.Collections.IEnumerator.Current 
     { 
      get { return _items[_index]; } 
     } 

     public bool MoveNext() 
     { 
      if (_items.Count == 0) 
      { 
       return false; 
      } 

      _index = (_index + 1) % _items.Count; 
      return true; 
     } 

     public void Reset() 
     { 
      _index = -1; 
     } 
    } 
+1

我更喜欢这个实现,因为它更加描述了你真正在做什么:无限列举列表。它感觉比无限IEnumerable的想法好得多,正如Ani提到的,​​它避免了大脑爆炸,即'ienum.Infinite()。Infinite()' – batwad 2010-08-26 14:06:37