web-dev-qa-db-ja.com

List <T>からn番目ごとのアイテムを取得するにはどうすればよいですか?

私は.NET 3.5を使用していますが、リストから* n *番目のすべてのアイテムを取得できるようにしたいと考えています。ラムダ式とLINQのどちらを使用して達成されたかは気にしません。

編集

この質問は非常に多くの議論を引き起こしたようです(これは良いことですよね?)。私が学んだ主なことは、あなたが何かをするためのあらゆる方法を知っていると思うとき(これほど簡単なことでも)、もう一度考えてみることです!

103
Paul Suart
return list.Where((x, i) => i % nStep == 0);
176
mqp

私はそれが「古い学校」であることを知っていますが、なぜstepping = nでforループを使用しないのですか?

37
Michael Todd

のように聞こえる

IEnumerator<T> GetNth<T>(List<T> list, int n) {
  for (int i=0; i<list.Count; i+=n)
    yield return list[i]
}

トリックを行います。 Linqやラムダ式を使用する必要はありません。

編集:

作る

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;

2回目の編集

さらにLINQishにするために

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

要素とともにインデックスを渡すWhereオーバーロードを使用できます

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

For Loop

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

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

LINQ式で実行できるかどうかはわかりませんが、Where拡張メソッドを使用して実行できることを知っています。たとえば、5つごとのアイテムを取得するには:

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

これにより、最初のアイテムが取得され、そこから5番目ごとに取得されます。最初ではなく5番目の項目から開始する場合は、0と比較する代わりに4と比較します。

3
Guffa

私の答えは正しくありません。すべてのソリューションは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];
}
0
user2340145
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
Anwar Ul Haq

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