【问题标题】:Multiple enumeration of IEnumerableIEnumerable的多重枚举
【发布时间】:2011-10-20 07:39:56
【问题描述】:

我知道 IEnumerable 已在此处讨论过多次,但我找不到特定问题的答案,因此我将其作为一个新问题提出。

考虑以下代码:

    static void Main(string[] args)
    {

        List<string> testList = new List<string> {"Test", "Test1", "Test1"};
        IEnumerable<string> filtered = testList.Where(x => x == "Test1");

        DoSomeWork(filtered);
        DoSomeMoreWork(filtered);
    }

    public static void DoSomeWork(IEnumerable<string> items)
    {
        foreach (var item in items)
        {
            Console.WriteLine("do some work");
        }
    }

    public static void DoSomeMoreWork(IEnumerable<string> items)
    {
        foreach (var item in items)
        {
            Console.WriteLine("do some more work");
        }
    }

我是对的,这不仅导致“过滤”中的两个项目迭代两次,而且实际上是“testList”中的项目?因此,考虑到“testList”是一个包含 10000 个项目的大列表,而“filtered”将其减少到 10 个项目,将“filtered”制作成一个列表会更聪明(也就是使用 var 并在末尾附加 ToList())

编辑: 这是我在这里问过的最尴尬的问题。例如,我知道迭代 IQueryable 会很糟糕,因为这会导致从数据库中获取数据两次。但是我不确定内存列表。如果可以的话,我会删除这个问题;-)

【问题讨论】:

    标签: linq ienumerable


    【解决方案1】:

    大名单将重复两次。要检查这是否真的发生,请将您的查询更改为:

    List<string> testList = new List<string> { "Test", "Test1", "Test1" };
    IEnumerable<string> filtered = from t in testList
                                   where t == "Test1"
                                   select t;
    

    如果您随后在 'where t == "Test1" 部分设置断点,您将看到调试器在两次迭代中都命中了这一行。

    【讨论】:

      【解决方案2】:

      大名单将重复两次。如果你不想要它,你可以“实现”这个限制。

      var filtered = testList.Where(x => x == "Test1").ToList();
      

      并且有很多答案可以告诉您这一点。你应该搜索得更好:-)

      【讨论】:

        【解决方案3】:

        列表最终是从 IEnumrable 继承的,检查一下

        public class List<T> : IList<T>, ICollection<T>, 
            IEnumerable<T>, IList, ICollection, IEnumerable
        

        您还可以使用以下可用的构造函数创建 IEnurable 列表

        public List(
            IEnumerable<T> collection
        )
        

        编辑

        这两种方法都会对派生的过滤列表进行两次迭代,但最后附加 .ToList() 方法。

        IEnumerable<string> filtered = testList.Where(x => x == "Test1").ToList();
        

        http://msdn.microsoft.com/en-us/library/fkbw11z0.aspx

        【讨论】:

        • 是的,我知道。但问题是。 DoSomeWork() 和 DoSomeMoreWork() 会导致迭代大列表还是只会迭代子集。
        • 最好使用 .ToArray 而不是 ToList 用于此用途:数组的效率更高,但最重要的是,它们不允许添加/删除,避免不必要的灵活性(从而避免混淆和错误)。跨度>
        • 我什至可以说,在 linq 代码中大量使用 List&lt;&gt; 通常是一种代码异味:它几乎从来都不是最好的解决方案。
        【解决方案4】:

        “过滤”一个列表会更聪明(也就是使用 var 并在末尾附加 ToList())

        是的,尤其是在 Linq-To-Entities 等方面。

        使用 linq 返回 IEnumerable 允许不同的执行。当您将ToList() 附加到末尾时,您的列表将在此处返回。

        http://blogs.msdn.com/b/charlie/archive/2007/12/09/deferred-execution.aspx

        【讨论】:

          猜你喜欢
          • 2014-06-13
          • 2011-04-03
          • 1970-01-01
          • 2012-01-04
          • 1970-01-01
          • 2012-07-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多