繁体   English   中英

如何从列表中获取第 n 个项目<T> ?

[英]How can I get every nth item from a List<T>?

我正在使用 .NET 3.5 并且希望能够从列表中获取每个 * n *th 项。 我并不担心它是使用 lambda 表达式还是 LINQ 实现的。

编辑

看起来这个问题引起了很多争论(这是一件好事,对吧?)。 我学到的主要事情是,当您认为自己知道做某事的所有方法时(即使像这样简单),请再想一想!

return list.Where((x, i) => i % nStep == 0);

我知道这是“老派”,但为什么不直接使用带有 stepping = n 的 for 循环?

听起来像

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

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

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

For循环

for(int i = 0; i < list.Count; i += n)
    //Nth Item..

我认为如果您提供 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];
    }
}

我不确定是否可以使用 LINQ 表达式,但我知道您可以使用Where扩展方法来执行此操作。 例如获取每五个项目:

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

这将获得第一个项目,从那里每五个项目。 如果要从第五项而不是第一项开始,则与 4 进行比较而不是与 0 进行比较。

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

输出

在此处输入图片说明

恕我直言,没有答案是正确的。 所有解决方案都从 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];
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM