【问题标题】:How to get first N elements of a list in C#?如何在 C# 中获取列表的前 N ​​个元素?
【发布时间】:2010-09-24 02:44:30
【问题描述】:

我想在我的项目中使用 Linq 查询公交时刻表,以便随时可以获取接下来的 5 趟公交车到达时间。如何将我的查询限制为前 5 个结果?

更一般地说,如何在 C# 中获取列表的一部分? (在 Python 中,我会使用 mylist[:5] 来获取前 5 个元素。)

【问题讨论】:

    标签: c#


    【解决方案1】:
    var firstFiveItems = myList.Take(5);
    

    或者切片:

    var secondFiveItems = myList.Skip(5).Take(5);
    

    当然,根据某种顺序获取前五个项目通常很方便:

    var firstFiveArrivals = myList.OrderBy(i => i.ArrivalTime).Take(5);
    

    【讨论】:

    • 如果列表中只有 3 个项目,它会抛出异常吗?还是需要多达 5 个?
    • @bobek :它不会抛出异常。如果没有足够的元素,它只会返回它所拥有的内容。
    • 没错,没有抛出异常 Skip 和 Take 结合解决了我的问题,因为我想要获取任何通用集合并处理每批 x 项
    • 需要注意的是.Take(n)返回的是TakeIterator;它不会返回包含 n 元素的列表(假设有很多可用)。在Take 的结果上使用.ToArray().ToList() 以获取具体的数组或列表。
    • 另外,看起来您实际上需要始终使用 OrderBy 的 ATM。这是 EntityFramework 在没有它的异常消息中告诉我的:The method 'Skip' is only supported for sorted input in LINQ to Entities. The method 'OrderBy' must be called before the method 'Skip'. 我假设“Take”是一样的,但我可能错了。
    【解决方案2】:

    如果有人感兴趣(即使问题没有要求这个版本),在 C# 2 中将是:(我已经编辑了答案,遵循了一些建议)

    myList.Sort(CLASS_FOR_COMPARER);
    List<string> fiveElements = myList.GetRange(0, 5);
    

    【讨论】:

    • 也许也可以添加一个匿名谓词?
    • List.Sort 返回 void;您需要排序,然后单独使用 GetRange。您还可以使用比较 匿名方法来消除对 CLASS_FOR_COMPARER 的需要。
    • @AlexeyMK - 你的意思是比较,而不是谓词 (Predicate) - 谓词用于过滤数据
    • 我相信这个答案即使在现在、10 年和许多 C# 版本之后仍然有用。对于您有列表的特定情况。特别是如果您要跳过许多项目。例如。您有一个包含 100 万个项目的列表,并且您想要其中的 5 个,在列表中很远。 GetRange 确切地知道去哪里抓取它们。我不知道Skip + Take 是否一样聪明,或者它是否枚举了跳过的项目。而且我不需要知道——我只使用 GetRange(当给定一个列表时)。只要确保你意识到第二个参数是 count(而不是 last index)。
    • .Take(n) 的好处在于,如果它处理的序列中的元素少于n,您不必担心。 List&lt;T&gt;.GetRange(0, count) 的问题是你必须担心....如果没有 count 项目,你会得到一个 ArgumentException
    【解决方案3】:

    pagination一样,你可以使用下面的公式来获取slice of list or elements

    var slice = myList.Skip((pageNumber - 1) * pageSize)
                      .Take(pageSize);
    

    示例 1:前五项

    var pageNumber = 1;
    var pageSize = 5;
    

    示例 2:后五项

    var pageNumber = 2;
    var pageSize = 5;
    

    示例3:第三五项

    var pageNumber = 3;
    var pageSize = 5;
    

    如果注意公式参数pageSize = 5pageNumber发生变化,如果要更改切片中的项目数,请更改pageSize

    【讨论】:

      【解决方案4】:

      要获取前 5 个元素,最好使用如下表达式:

      var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5);

      var firstFiveArrivals = myList.Where([EXPRESSION]).Take(5).OrderBy([ORDER EXPR]);

      它会比 orderBy 变体更快,因为 LINQ 引擎由于执行延迟而不会扫描所有列表,并且不会对所有数组进行排序。

      class MyList : IEnumerable<int>
      {
      
          int maxCount = 0;
      
          public int RequestCount
          {
              get;
              private set;
          }
          public MyList(int maxCount)
          {
              this.maxCount = maxCount;
          }
          public void Reset()
          {
              RequestCount = 0;
          }
          #region IEnumerable<int> Members
      
          public IEnumerator<int> GetEnumerator()
          {
              int i = 0;
              while (i < maxCount)
              {
                  RequestCount++;
                  yield return i++;
              }
          }
      
          #endregion
      
          #region IEnumerable Members
      
          System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
          {
              throw new NotImplementedException();
          }
      
          #endregion
      }
      class Program
      {
          static void Main(string[] args)
          {
              var list = new MyList(15);
              list.Take(5).ToArray();
              Console.WriteLine(list.RequestCount); // 5;
      
              list.Reset();
              list.OrderBy(q => q).Take(5).ToArray();
              Console.WriteLine(list.RequestCount); // 15;
      
              list.Reset();
              list.Where(q => (q & 1) == 0).Take(5).ToArray();
              Console.WriteLine(list.RequestCount); // 9; (first 5 odd)
      
              list.Reset();
              list.Where(q => (q & 1) == 0).Take(5).OrderBy(q => q).ToArray();
              Console.WriteLine(list.RequestCount); // 9; (first 5 odd)
          }
      }
      

      【讨论】:

      • 除了您现在只订购选择它们后的前 5 个元素。它可能更快,但它也有不同的语义,这不太可能是人们真正想要实现的目标。
      【解决方案5】:
              dataGridView1.DataSource = (from S in EE.Stagaire
                                          join F in EE.Filiere on
                                          S.IdFiliere equals F.IdFiliere
                                          where S.Nom.StartsWith("A")
                                          select new
                                          {
                                              ID=S.Id,
                                              Name = S.Nom,
                                              Prénon= S.Prenon,
                                              Email=S.Email,
                                              MoteDePass=S.MoteDePass,
                                              Filiere = F.Filiere1
                                          }).Take(1).ToList();
      

      【讨论】:

      • 您好 Mouad,感谢您的回答。虽然您的代码可能会解决已发布问题中的问题,但好的答案可以解释为什么您的解决方案有效。请考虑更新您的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-23
      • 1970-01-01
      • 2012-02-16
      • 2013-06-19
      • 2010-12-21
      • 2011-02-10
      相关资源
      最近更新 更多