如何从 List < T > 中获取每个 n 项?

我在吸毒。NET 3.5,并希望能够从列表中获得每个 * n * 项。我并不担心它是通过使用 lambda 表达式还是 LINQ 实现的。

剪辑

看起来这个问题引起了相当多的争论(这是一件好事,对吗?).我学到的最重要的一点是,当你认为你知道做某事的每一种方法(甚至像这样简单)时,再想想!

93600 次浏览

我知道这是“老式的”,但是为什么不用带 step = n 的 for 循环呢?

为了鲁普

for(int i = 0; i < list.Count; i += n)
//Nth Item..
return list.Where((x, i) => i % nStep == 0);

听起来像

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];
}
}

你用林奇的方式写作

from var element in MyList.GetNth(10) select element;

第二次编辑 :

让它更像林奇

from var i in Range(0, ((myList.Length-1)/n)+1) select list[n*i];

可以使用 Where 重载将索引与元素一起传递

var everyFourth = list.Where((x,i) => i % 4 == 0);

我不确定是否可以使用 LINQ 表达式,但是我知道可以使用 Where扩展方法来实现。例如,获得每五个项目:

List<T> list = originalList.Where((t,i) => (i % 5) == 0).ToList();

这个会得到第一个项目,每五个从那里。如果希望从第五项开始,而不是从第一项开始,那么可以用4来比较,而不是用0来比较。

我认为,如果您提供了 linq 扩展,那么您应该能够在最不具体的接口上进行操作,因此可以在 IEnumable 上进行操作。当然,如果你的速度特别是大 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];
}
}
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();
}

输出

enter image description here

没有答案是正确的。所有的解从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];
}

@ 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];
}
}