如何使用 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.Select( x=>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 从列表中选择提供的索引范围内的值的主要内容,如果未能解决你的问题,请参考以下文章