如何从List <t>获取每个第n项?</t>

时间:2009-03-25 17:27:56

标签: c# linq list lambda

我正在使用.NET 3.5,并且希望能够从列表中获取每个* n *项。我对使用lambda表达式还是LINQ来实现它并不感到困扰。

修改

看起来这个问题引起了很多争论(这是一件好事,对吧?)。我学到的主要内容是,当你认为你知道做某事的每一种方式时(尽管这很简单),再想一想!

10 个答案:

答案 0 :(得分:170)

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

答案 1 :(得分:36)

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

答案 2 :(得分:33)

听起来像

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

答案 3 :(得分:25)

您可以使用传递索引的Where重载以及元素

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

答案 4 :(得分:10)

For Loop

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

答案 5 :(得分:3)

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

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

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

答案 6 :(得分:3)

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

答案 7 :(得分:0)

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

答案 8 :(得分:0)

Imho没有回答是对的。所有解决方案都从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 :(得分: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];
        }
    }