获取LINQ中前x个元素和后x个元素的子集

3

我有一个列表,需要从中选出当前for循环中前5个元素和后5个元素组成的子列表,总共10个元素。忽略循环中的当前元素。

我目前是这样实现的:

var currentIndex = myList.ClassName.FindIndex(a => a.Id == plate.Id);
var fromIndex = currentIndex - 5;
if (fromIndex < 0) fromIndex = 0;
var toIndex = currentIndex + 5;
if ((myList.ClassName.ElementAtOrDefault(toIndex) == null))
    toIndex = myList.ClassName.Count - 1;


var subsetList = myList.ClassName.GetRange(fromIndex, (11));
comparisonPlates.RemoveAt(currentIndex);

然而,我相信使用LINQ有更好的、更高效的方法来做到这一点,有何指导?

2
如果你的逻辑如此依赖于索引,那么你不应该使用 LINQ。这既不可读也不高效。 - Tim Schmelter
我只需要最有效的方法来获取前面和后面的元素子集。 - Tommy
如果你当前的方法可行,就继续使用它。List.GetRange正是你所需要的。 - Tim Schmelter
我已经编辑了你的标题。请参考“问题的标题应该包含“标签”吗?”,在那里达成共识是“不应该”。 - John Saunders
3个回答

2
我会使用SkipTake,这样你就可以拥有所有围绕当前索引(以及当前索引本身)的元素。
要删除当前索引,可以添加RemoveAt;或者使用多个Skip/Take(Skip/Take用于获取你之前的元素和之后的元素)。
以下是一个示例:
const int currentIndex = 12;
const int nbElements = 5;
List<string> results = items.Skip(currentIndex - nbElements).Take(nbElements).Concat(items.Skip(currentIndex + 1).Take(nbElements)).ToList();

不确定如何正确使用这个,请提供一个可行的例子? - Tommy
请注意,Union 返回不同的值。在这种情况下,Concat 更合适。 - Ripple

1
我建议您使用LINQ来生成索引:
var subset = Enumerable.Range(currentIndex - 5, 5)
    .Concat(Enumerable.Range(currentIndex + 1, 5))
    .SkipWhile(index => index < 0)
    .TakeWhile(index => index < items.Count)
    .Select(index => items[index])
    ;

这种方法比使用items.Skip操作更高效,因为items.Skip(n)会内部通过一个接一个的枚举器IEnumerator.MoveNext浏览n个元素,也就是说,你的currentIndex越大,效率越低。
当然,上面代码中的SkipWhileTakeWhile由于同样的原因略微低效,但它总是只循环10次。
如果你讨厌这种低效率,可以预先计算索引和计数(Enumerable.Range的参数)并消除它们。(在我看来,上述代码似乎更易读。)
此外,List的索引器([])的运行时复杂度为O(1),这意味着items[index]花费的时间是恒定的,无论index值或List的大小如何。

1
这里有一个我认为更易读的解决方案。
var numElements = 5;
var fromIndex = currentIndex <= numElements ? 0 : currentIndex - numElements - 1;
var toIndex = myList.Count() - currentIndex <= numElements ? myList.Count() : currentIndex + numElements;

var subsetList = myList.Skip(fromIndex).Take(toIndex - fromIndex);

编辑:

我建议使用Ripple的答案,因为提到了性能原因。我之前不知道跳过/取出的影响,但是查找后,它确实有道理。对于少量项目列表,这并不重要,但对于大量数据来说就很重要。


你仍然必须删除当前元素。 - Askolein

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接