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


114

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

編集する

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


元の質問の背後にある意味は編集していません。私はそれをクリーンアップし、大文字と句読点を正しく使用しました。(.NETは大文字、LINQはすべて大文字で、「ラムダ」ではなく、「ラムダ式」です。)
ジョージストッカー

1
「fussed」を「類義語」ではない「sure」に置き換えました。
mqp 2009年

そう思われるでしょう。「...を使用して達成できるかどうかわからない」でない限り、確認しても意味がありません。
Samuel

はい、私が理解しているように、それはほぼ正しいです。
mqp

「ラムダ式とLINQのどちらを使用して達成されるかは関係ない」と書かれるように、「心配」に置き換えるのがおそらく最善です。
TheTXI 2009年

回答:


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

5
@mquander:これは実際にはn番目-1の要素を与えることに注意してください。実際のn番目の要素が必要な場合(最初の要素をスキップ)、iに1を追加する必要があります。
casperOne 2009年

2
はい、私はそれがあなたが「nth」によって何を意味するかに依存すると思いますが、あなたの解釈はより一般的かもしれません。必要に応じて、iを加算または減算します。
mqp 2009年

5
注意してください:Linq / Lambdaソリューションは、固定増分の単純なループよりもパフォーマンスがはるかに低くなります。
MartinStettner 2009年

5
必ずしもそうとは限りませんが、遅延実行では、foreachループで使用でき、元のリストを1回だけループします。
サミュエル、

1
それはあなたが「実用的」とはどういう意味かによって異なります。ユーザーがボタンをクリックしたときに30アイテムのリストから他のすべてのアイテムをすばやく取得する方法が必要な場合は、これがすべて実用的だと思います。時々、パフォーマンスはもはや重要ではありません。もちろん、時々そうします。
mqp 2009年

37

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


それは基本的に私の考えでした。
マーク・ピム

1
@Michael Todd:動作しますが、問題はどこにでもその機能を複製する必要があることです。LINQを使用すると、構成されたクエリの一部になります。
casperOne 2009年

8
@casperOne:プログラマはこれを処理するためにサブルーチンと呼ばれるものを発明したと思います;)実際のプログラムでは、ループはすべての要素を繰り返す必要がないため、賢いLINQバージョンにもかかわらず、おそらくループを使用します(インデックスをNずつインクリメントします。)
mqp 2009年

私は古い学校の解決策に行くことに同意します、そしてこれはより良く実行すると推測しています。
Jesper Fyhr Knudsen

派手な新しい構文を使いこなすのは簡単です。でも楽しいです。
ロニー

34

のように聞こえる

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

2
基本的にIEnumerableのすべての要素を反復するWhere()メソッドの代わりにthis []ゲッターを使用するためのこのメソッドが好きです。IList / ICollectionタイプがある場合、これがより良いアプローチです。
スポールソン2009年

リストがどのように機能するかわかりませんが、なぜループを使用して、list[i]代わりに単にreturnを返すのlist[n-1]ですか?
ファンカルロスオロペサ

@JuanCarlosOropeza彼はリストのn番目の要素だけでなく、n番目ごとの要素(たとえば、0、3、6 ...)を返します。
alfoks 2017年


10

ループ

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

カウントは列挙可能なものを評価します。これがlinqフレンドリーな方法で行われた場合は、遅延評価して最初の100の値を取ることができます。評価対象の要素
RhysC 2015

1
@RhysC良い点、一般的な列挙可能オブジェクト。OTOH、質問は指定しなかったList<T>ので、Count安くなるように定義されます。
ToolmakerSteve

3

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

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

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


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

これはどのリストでも機能しますか?カスタムクラスのリストで使用して<class>ではなくIEnumarted <class>を返そうとして、強制的に(class)List.GetNth(1)を強制しても機能しないためです。
フアンカルロスオロペサ2015年

私のせいで、GetNth(1).FirstOrDefault();を含める必要がありました。
ファンカルロスオロペサ

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

出力

ここに画像の説明を入力してください


0

いも正解はありません。すべての解は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

@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];
        }
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.