如何从 List<T> 中获取每个第 n 个项目?
Posted
技术标签:
【中文标题】如何从 List<T> 中获取每个第 n 个项目?【英文标题】:How can I get every nth item from a List<T>? 【发布时间】:2009-03-25 17:27:55 【问题描述】:我正在使用 .NET 3.5,并且希望能够从列表中获取每个 *n
* 项。我不关心它是使用 lambda 表达式还是 LINQ 实现的。
编辑
看起来这个问题引起了很多争论(这是一件好事,对吧?)。我学到的主要一点是,当您认为自己知道做某事的所有方法(即使是这么简单)时,请再想一想!
【问题讨论】:
我没有删掉你原来问题背后的任何含义;我只清理了它并正确使用了大写和标点符号。 (.NET 是大写的,LINQ 是全大写的,它不是“lambda”,而是一个“lambda 表达式”。) 您将“fussed”替换为“sure”,而这根本不是同义词。 似乎是这样。确定也没有意义,除非它是“我不确定是否可以使用......” 是的,据我了解,差不多。 fussed 可能最好替换为“关注”,这样它就会显示为“我不关心它是使用 lambda 表达式还是 LINQ 实现的。” 【参考方案1】:return list.Where((x, i) => i % nStep == 0);
【讨论】:
@mquander:请注意,这实际上会给您第 n - 1 个元素。如果您想要实际的第 n 个元素(跳过第一个元素),那么您必须将 1 添加到 i。 是的,我想这有点取决于您所说的“nth”是什么意思,但您的解释可能更常见。从 i 中添加或减去以满足您的需要。 请注意:Linq/Lambda 解决方案的性能将远低于具有固定增量的简单循环。 不一定,通过延迟执行,它可以用于 foreach 循环,并且只在原始列表上循环一次。 这取决于您所说的“实用”。如果您需要一种在用户单击按钮时快速获取 30 个项目列表中的所有其他项目的方法,我会说这非常实用。有时性能真的不再重要了。当然,有时确实如此。【参考方案2】:我知道这是“老派”,但为什么不直接使用带有 stepping = n 的 for 循环呢?
【讨论】:
这基本上是我的想法。 @Michael Todd:它有效,但问题是您必须在任何地方复制该功能。通过使用 LINQ,它成为组合查询的一部分。 @casperOne:我相信程序员发明了这个叫做子例程的东西来处理这个问题;)在一个真正的程序中,我可能会使用循环,尽管有聪明的 LINQ 版本,因为循环意味着你不需要'必须遍历每个元素(将索引增加 N。) 我同意使用老派的解决方案,我什至猜测这会表现得更好。 很容易被花哨的新语法迷住。不过很有趣。【参考方案3】:听起来像
IEnumerator<T> GetNth<T>(List<T> list, int n)
for (int i=0; i<list.Count; i+=n)
yield return list[i]
会成功的。我认为不需要使用 Linq 或 lambda 表达式。
编辑:
做起来
public static class MyListExtensions
public static IEnumerable<T> GetNth<T>(this List<T> list, int n)
for (int i=0; i<list.Count; i+=n)
yield return list[i];
你用 LINQish 的方式写作
from var element in MyList.GetNth(10) select element;
第二次编辑:
让它更加 LINQish
from var i in Range(0, ((myList.Length-1)/n)+1) select list[n*i];
【讨论】:
我喜欢这种使用 this[] getter 而不是 Where() 方法的方法,它本质上是迭代 IEnumerable 的每个元素。如果您有 IList/ICollection 类型,这是更好的方法,恕我直言。 不确定列表是如何工作的,但为什么你使用循环并返回list[i]
而只是返回 list[n-1]
?
@JuanCarlosOropeza 他返回每个第 n 个元素(例如 0、3、6...),而不仅仅是列表的第 n 个元素。【参考方案4】:
您可以使用 Where 重载将索引与元素一起传递
var everyFourth = list.Where((x,i) => i % 4 == 0);
【讨论】:
得说我是这种方法的粉丝。 我一直忘记你可以做到这一点 - 非常好。【参考方案5】:for循环
for(int i = 0; i < list.Count; i += n)
//Nth Item..
【讨论】:
Count 将评估可枚举。如果这是以 linq 友好的方式完成的,那么您可以懒惰地评估并获取前 100 个值,例如 ``source.TakeEvery(5).Take(100) `` 如果基础源的评估成本很高,那么您的方法将导致每个要评估的元素 @RhysC 好点,对于一般的可枚举。 OTOH,问题确实指定了List<T>
,所以Count
被定义为便宜。【参考方案6】:
我认为如果你提供一个 linq 扩展,你应该能够在最不具体的接口上操作,因此在 IEnumerable 上。当然,如果您想提高速度,尤其是对于大 N,您可能会为索引访问提供过载。后者消除了对大量不需要的数据进行迭代的需要,并且比 Where 子句要快得多。提供这两个重载可以让编译器选择最合适的变体。
public static class LinqExtensions
public static IEnumerable<T> GetNth<T>(this IEnumerable<T> list, int n)
if (n < 0)
throw new ArgumentOutOfRangeException("n");
if (n > 0)
int c = 0;
foreach (var e in list)
if (c % n == 0)
yield return e;
c++;
public static IEnumerable<T> GetNth<T>(this IList<T> list, int n)
if (n < 0)
throw new ArgumentOutOfRangeException("n");
if (n > 0)
for (int c = 0; c < list.Count; c += n)
yield return list[c];
【讨论】:
这适用于任何列表吗?因为我尝试在 List 中使用自定义类并返回 IEnumarted我不确定是否可以使用 LINQ 表达式,但我知道您可以使用 Where
扩展方法来做到这一点。例如获取每五个项目:
List<T> list = originalList.Where((t,i) => (i % 5) == 0).ToList();
这将获得第一个项目,然后每五分之一。如果要从第 5 项而不是第 1 项开始,则与 4 进行比较,而不是与 0 进行比较。
【讨论】:
【参考方案8】:恕我直言,没有答案是正确的。所有解决方案都从 0 开始。但我想要真正的第 n 个元素
public static IEnumerable<T> GetNth<T>(this IList<T> list, int n)
for (int i = n - 1; i < list.Count; i += n)
yield return list[i];
【讨论】:
【参考方案9】:@belucha 我喜欢这个,因为客户端代码可读性很强,编译器会选择最高效的实现。我会以此为基础,将要求降低到 IReadOnlyList<T>
,并为高性能 LINQ 保留部门:
public static IEnumerable<T> GetNth<T>(this IEnumerable<T> list, int n)
if (n <= 0) throw new ArgumentOutOfRangeException(nameof(n), n, null);
int i = n;
foreach (var e in list)
if (++i < n) //save Division
continue;
i = 0;
yield return e;
public static IEnumerable<T> GetNth<T>(this IReadOnlyList<T> list, int n
, int offset = 0) //use IReadOnlyList<T>
if (n <= 0) throw new ArgumentOutOfRangeException(nameof(n), n, null);
for (var i = offset; i < list.Count; i += n)
yield return list[i];
【讨论】:
【参考方案10】:private static readonly string[] sequence = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15".Split(',');
static void Main(string[] args)
var every4thElement = sequence
.Where((p, index) => index % 4 == 0);
foreach (string p in every4thElement)
Console.WriteLine("0", p);
Console.ReadKey();
输出
【讨论】:
以上是关于如何从 List<T> 中获取每个第 n 个项目?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 C# 中的通用 List<T> 中获取元素? [复制]