【问题标题】:How to select values within a provided index range from a List using LINQ如何使用 LINQ 从列表中选择提供的索引范围内的值
【发布时间】:2010-11-05 17:44:12
【问题描述】:

我是一个 LINQ 新手,试图用它来实现以下目标:

我有一个整数列表:-

List<int> intList = new List<int>(new int[]{1,2,3,3,2,1});

现在,我想使用 LINQ 比较前三个元素 [索引范围 0-2] 与后三个 [索引范围 3-5] 的总和。我尝试了 LINQ Select 和 Take 扩展方法以及 SelectMany 方法,但我不知道该怎么说

(from p in intList  
where p in  Take contiguous elements of intList from index x to x+n  
select p).sum()

我也查看了 Contains 扩展方法,但这并没有得到我想要的东西。有什么建议?谢谢。

【问题讨论】:

    标签: c# linq list range


    【解决方案1】:

    使用Skip,然后使用。

    yourEnumerable.Skip(4).Take(3).Select( x=>x )
    
    (from p in intList.Skip(x).Take(n) select p).sum()
    

    【讨论】:

    • 请注意 List.GetRange 将更有效,但对于较大的集合:icodeit.wordpress.com/2012/08/27/…, geekswithblogs.net/BlackRabbitCoder/archive/2012/03/29/…
    • 这是一个很好的、有效的评论(几年前我曾投票支持下面的答案作者,他说了同样的话),尽管 OP 专门询问了 LINQ,所以你不能真的保证 List 作为您的来源。这可能是实际问题的简化版本,其中简化版本只是一个硬编码的 List(并且可能实际上是对象图上的查询或 LINQ to SQL 查询)。
    • .Select( x=&gt;x ) 的意义何在?在这种情况下它实际上什么都不做吗?
    【解决方案2】:

    你可以使用 GetRange()

    list.GetRange(index, count);
    

    【讨论】:

    • 这个功能在哪里? .NET 4.5 还是什么?
    • @AdamNofsinger 这是在 System.Collections.Generic 命名空间下。它带有.Net 2.0。 msdn.microsoft.com/en-us/library/21k0e39c(v=vs.80).aspx
    • 值得注意的是,这是在IList 接口上,因此不适用于更常见的IEnumerable。部分原因是为了防止人们在脚部表现方面对自己进行射击(即,如果一个集合在 O(1) 时间内不可索引,这可能需要 O(n) 时间,也许是出乎意料的)。它还返回一个新列表,而不是像 LINQ 那样作为原始列表顶部的外观。
    【解决方案3】:

    对于较大的列表,单独的扩展方法可能更适合性能。我知道这对于初始情况不是必需的,但是 Linq(对象)实现依赖于迭代列表,因此对于大型列表,这可能(毫无意义)昂贵。实现此目的的简单扩展方法可能是:

    public static IEnumerable<TSource> IndexRange<TSource>(
        this IList<TSource> source,
        int fromIndex, 
        int toIndex)
    {
        int currIndex = fromIndex;
        while (currIndex <= toIndex)
        {
            yield return source[currIndex];
            currIndex++;
        }
    }
    

    【讨论】:

      【解决方案4】:

      按特定索引(不是从-到)过滤:

      public static class ListExtensions
      {
         public static IEnumerable<TSource> ByIndexes<TSource>(this IList<TSource> source, params int[] indexes)
         {        
              if (indexes == null || indexes.Length == 0)
              {
                  foreach (var item in source)
                  {
                      yield return item;
                  }
              }
              else
              {
                  foreach (var i in indexes)
                  {
                      if (i >= 0 && i < source.Count)
                          yield return source[i];
                  }
              }
         }
      }
      

      例如:

      string[] list = {"a1", "b2", "c3", "d4", "e5", "f6", "g7", "h8", "i9"};
      var filtered = list.ByIndexes(5, 8, 100, 3, 2); // = {"f6", "i9", "d4", "c3"};
      

      【讨论】:

        【解决方案5】:

        从 .NET 6 开始,可以使用 range syntax 作为 Take 方法。

        List<int> intList = new List<int>(new int[]{1, 2, 3, 3, 2, 1});
        
        // Starting from index 0 (including) to index 3 (excluding) will select indexes (0, 1, 2)
        Console.WriteLine(intList.Take(0..3).Sum()); // {1, 2, 3} -> 6
        
        // By default is first index 0 and can be used following shortcut.
        Console.WriteLine(intList.Take(..3).Sum());  // {1, 2, 3} -> 6      
        
        
        // Starting from index 3 (including) to index 6 (excluding) will select indexes (3, 4, 5)
        Console.WriteLine(intList.Take(3..6).Sum()); // {3, 2, 1} -> 6  
        
        // By default is last index lent -1 and can be used following shortcut.
        Console.WriteLine(intList.Take(3..).Sum());  // {3, 4, 5} -> 6
        
        // Reverse index syntax can be used. Take last 3 items.
        Console.WriteLine(intList.Take(^3..).Sum()); // {3, 2, 1} -> 6
        
        // No exception will be raised in case of range is exceeded.
        Console.WriteLine(intList.Take(^100..1000).Sum()); 
        

        简单地说,intList.Take(..3).Sum()intList.Take(3..).Sum() 可以与 .NET 6 一起使用。

        【讨论】:

          猜你喜欢
          • 2021-09-10
          • 1970-01-01
          • 2021-09-14
          • 1970-01-01
          • 1970-01-01
          • 2021-10-06
          • 1970-01-01
          • 2021-06-13
          • 1970-01-01
          相关资源
          最近更新 更多