web-dev-qa-db-ja.com

Linqを使用して、リストからすべての一致する値のインデックスを取得します

ちょっとLinqの専門家は、

私は非常に似た質問をして、解決策はおそらく非常に簡単だと知っていますが、linqを使用して最も効率的な方法でこの非常に簡単なタスクをどのように行うかについて頭を悩ませることができません。

私の基本的なシナリオは、次のような値のリストがあることです。

Lst1:
a
a
b
b
c
b
a
c
a

そして、たとえば、値= "a"であるLst1のすべてのインデックスを保持する新しいリストを作成します。したがって、この例では次のようになります。

LstIndexes:
0
1
6
8

今、私はループでこれを行うことができることを知っています(Linqを支持してむしろ避けたいです)、そして私は次の方法でLinqでこれを行う方法を見つけました:

LstIndexes= Lst1.Select(Function(item As String, index As Integer) index) _
                .Where(Function(index As Integer) Lst1(index) = "a").ToList

これに関する私の課題は、リストを2回反復するため、効率が悪いことです。

Linqを使用して最も効率的な方法で結果を取得するにはどうすればよいですか?

ありがとう!!!!

27
John Bustos

まず、コードは実際にリストを2回反復するのではなく、1回だけ反復します。

つまり、Selectは実際にはすべてのインデックスのシーケンスを取得しているだけです。それはEnumerable.Range

var result = Enumerable.Range(0, lst1.Count)
             .Where(i => lst1[i] == "a")
             .ToList();

リストが実際に2回繰り返されない理由を理解するには、ある程度慣れる必要があります。基本的な説明をしようと思います。

SelectやWhereなどのほとんどのLINQメソッドをパイプラインとして考える必要があります。各メソッドは、わずかな作業を行います。 Selectの場合、メソッドを与えると、「誰かが私の次のアイテムを要求するたびに、最初に入力シーケンスにアイテムを要求し、それから別の何かに変換するメソッドを使用します。そして、そのアイテムを私を使っている人に渡してください。」 Whereは、多かれ少なかれ、「誰かがアイテムを要求するたびに、アイテムの入力シーケンスを要求します。関数がそれが良ければ、それを渡します。そうでない場合は、アイテムを要求し続けます。合格するまで」

したがって、それらをチェーンすると、ToListは最初の項目を要求し、最初の項目としてWhereに移動し、WhereSelectに移動して最初の項目を要求し、Selectは最初の項目を要求します項目。リストは、最初のアイテムを提供します。 Selectは、そのアイテムを吐き出すために必要なもの(この場合はint 0のみ)に変換し、Whereに渡します。 Whereはそのアイテムを受け取り、それが真であると判断する関数を実行します。したがって、0ToListに追加すると、リストに追加されます。その後、そのすべてがさらに9回発生します。これは、Selectがリストから各項目を1回だけ要求することを意味し、各結果をWhereに直接フィードします。これにより、「テストに合格」した結果がToListに直接送られ、リストに保存されます。すべてのLINQメソッドは、ソースシーケンスを1回のみ(1回反復する場合)反復するように慎重に設計されています。

これは最初は複雑に思えますが、実際にはコンピューターがこれをすべて簡単に実行できることに注意してください。実際には、最初に思えるかもしれないほどパフォーマンスが集中しているわけではありません。

60
Servy

これは機能しますが、間違いなく適切ではありません。

var result = list1.Select((x, i) => new {x, i})
                  .Where(x => x.x == "a")
                  .Select(x => x.i);
7
Jim Johnson

これはどうですか、私にとってはかなりうまくいきます。

   static void Main(string[] args)
    {
        List<char> Lst1 = new List<char>();
        Lst1.Add('a'); 
        Lst1.Add('a');   
        Lst1.Add('b');   
        Lst1.Add('b');   
        Lst1.Add('c');   
        Lst1.Add('b');   
        Lst1.Add('a');   
        Lst1.Add('c');
        Lst1.Add('a');

        var result = Lst1.Select((c, i) => new { character = c, index = i })
                         .Where(list => list.character == 'a')
                         .ToList();
    }
1
luis_laurent