如何使用 LINQ 从列表中选择提供的索引范围内的值

Posted

技术标签:

【中文标题】如何使用 LINQ 从列表中选择提供的索引范围内的值【英文标题】:How to select values within a provided index range from a List using 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 扩展方法,但这并没有得到我想要的东西。有什么建议?谢谢。

【问题讨论】:

【参考方案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 一起使用。

【讨论】:

以上是关于如何使用 LINQ 从列表中选择提供的索引范围内的值的主要内容,如果未能解决你的问题,请参考以下文章

使用 Linq 从列表中获取所有匹配值的索引

构建 LINQ 表达式树:如何获取范围内的变量

Linq to SQL 选择 DateTime 字段在任何日期范围列表中的行

如何匹配具有相同索引位置的 2 个列表?

使用Linq获取列表中对象的索引[重复]

如何从特定小时范围内的行中选择最小值?