【问题标题】:Enumerate through a subset of a Collection in C#?在 C# 中枚举集合的子集?
【发布时间】:2009-05-19 20:00:00
【问题描述】:

在 C# 中是否有一种仅枚举集合的子集的好方法?也就是说,我有一个包含大量对象(例如 1000 个)的集合,但我只想枚举 250 - 340 个元素。有没有一种好方法可以为集合的子集获取枚举器,而无需使用其他收藏?

编辑:应该提到这是使用 .NET Framework 2.0。

【问题讨论】:

    标签: c# collections .net-2.0 enumeration subset


    【解决方案1】:

    试试下面的

    var col = GetTheCollection();
    var subset = col.Skip(250).Take(90);
    

    或者更一般的

    public static IEnumerable<T> GetRange(this IEnumerable<T> source, int start, int end) {
      // Error checking removed
      return source.Skip(start).Take(end - start);
    }
    

    编辑 2.0解决方案

    public static IEnumerable<T> GetRange<T>(IEnumerable<T> source, int start, int end ) {
      using ( var e = source.GetEnumerator() ){ 
        var i = 0;
        while ( i < start && e.MoveNext() ) { i++; }
        while ( i < end && e.MoveNext() ) { 
          yield return e.Current;
          i++;
        }
      }      
    }
    
    IEnumerable<Foo> col = GetTheCollection();
    IEnumerable<Foo> range = GetRange(col, 250, 340);
    

    【讨论】:

    • 我喜欢这种扩展方法。
    • 对不起,这是使用 .NET 2.0;跳过不可用。不过,如果它是在 .NET 3.5 中,那将是黄金。
    • @McWafflestix 添加了 2.0 解决方案
    • 在 2.0 中可以解决问题;不像 3.5 那样简洁,但它可以工作。
    • @McWafflestix,是的。 LINQ 的优点之一就是简洁
    【解决方案2】:

    我喜欢保持简单(如果您不一定需要枚举器):

    for (int i = 249; i < Math.Min(340, list.Count); i++)
    {
        // do something with list[i]
    }
    

    【讨论】:

    • 这比公认的答案简单得多......而且在我看来,如果我们要获得非常大列表末尾的项目,这具有优势。接受的答案将不必要地从一开始就遍历。 ...考虑到这一切,我很困惑为什么这个答案的支持率如此之低。我是否错过了有关此答案的一些技术性内容?或者只是你在另一个被接受后发布这个答案,所以没有多少人真正看到它。
    • @AmithGeorge 大多数其他答案适用于所有实现 IEnumerable 的集合。此答案仅对想要实现 IList 或其他数字索引器/下标的人有用。我希望这能解决问题。
    【解决方案3】:

    将 Jared 的原始代码改编为 .Net 2.0:

    IEnumerable<T> GetRange(IEnumerable<T> source, int start, int end)
    {
        int i = 0;
        foreach (T item in source)
        {
            i++;
            if (i>end) yield break;
            if (i>start) yield return item;
        }
    }
    

    并使用它:

     foreach (T item in GetRange(MyCollection, 250, 340))
     {
         // do something
     }
    

    【讨论】:

      【解决方案4】:

      再次改编 Jarad 的代码,这种扩展方法将为您提供由 item 定义的子集,而不是索引。

          //! Get subset of collection between \a start and \a end, inclusive
          //! Usage
          //! \code
          //! using ExtensionMethods;
          //! ...
          //! var subset = MyList.GetRange(firstItem, secondItem);
          //! \endcode
      class ExtensionMethods
      {
          public static IEnumerable<T> GetRange<T>(this IEnumerable<T> source, T start, T end)
          {
      #if DEBUG
              if (source.ToList().IndexOf(start) > source.ToList().IndexOf(end))
                  throw new ArgumentException("Start must be earlier in the enumerable than end, or both must be the same");
      #endif
              yield return start;
      
              if (start.Equals(end))
                  yield break;                                                    //start == end, so we are finished here
      
              using (var e = source.GetEnumerator())
              { 
                  while (e.MoveNext() && !e.Current.Equals(start));               //skip until start                
                  while (!e.Current.Equals(end) && e.MoveNext())                  //return items between start and end
                      yield return e.Current;
              }
          }
      }
      

      【讨论】:

        【解决方案5】:

        你也许可以用 Linq 做一些事情。我这样做的方法是将对象放入数组中,然后我可以根据数组 id 选择要处理的项目。

        【讨论】:

          【解决方案6】:

          如果您发现需要对列表和集合进行大量切片和切块,则可能值得将学习曲线攀登到 the C5 Generic Collection Library

          【讨论】:

            猜你喜欢
            • 2010-10-05
            • 1970-01-01
            • 2020-08-10
            • 2012-10-29
            • 1970-01-01
            • 1970-01-01
            • 2012-02-18
            • 2015-10-14
            • 2013-01-25
            相关资源
            最近更新 更多