2017-02-06 6 views
1

Linqには、条件に一致する最初に選択されたオカレンスの値を設定する方法はありますか?Linq Select:最初のオカレンスに特定の値を設定する

は、私はこれも説明していないよ知っているが、例えば:

var mySelectedObjects = allMyObjects.OrderBy(o.Date).Select(o => new ObjectType 
{ 
    Element1 = o.Element1, 
    Element2 = o.Element2, 
    Date = o.Date, 
    BooleanElement = o.BooleanElement && ThisIsTheFirstTrue 
}; 

したがって、上記の例では、所望の出力結果は mySelectedObjectsにアイテムのみ 最初に当てはまるだろうということです出現 allMyObjectsDateの順)になり、残りの部分はすべて allMyObjectsの値にかかわらずすべて偽になります。

つまり、私は、 = trueの1つ(最も早い)の出現をmySelectedObjectsに入れたいだけです。 ThisIsTheFirstTrueを何に置き換える必要がありますか?

編集

私はこれを実現するには、選択した後forループで行うことができますが、私は選択の中にそれをすべて行うことを期待しています。

とにかく、提案に応じて明確にすること。入力データがある場合、私は、私は、出力が

になりたい

false 
true 
false 
true 
true 
false 

...例えばそれは、入力中に本当の最初の発生のための真になりたいだけではなく、最初に出現したので、

false 
true 
false 
false 
false 
false 
+0

- 他の二つの 'true'の値が出力に行ってなぜですか? –

+0

@ SergeyBerezovskiy - それは私がやろうとしていることの要件です。 (この場合、ブール値はXAMLフォームの 'Visibility'属性にバインドされ、毎回1つの項目しか表示しません) – colmde

+0

この機能はSelectで実装する必要がありますか、それとも一般的なLinqベースのアプローチで十分ですか? – TheJP

答えて

3

のでLinqを使用して:あなたの編集のために

bool found = false; 
var mySelectedObjects = objects 
    .OrderBy(o => o.Date) 
    .Select(o => new ObjectType 
    { 
     Element1 = o.Element1, 
     Element2 = o.Element2, 
     Date = o.Date, 
     BooleanElement = !found && o.BooleanElement ? (found = true) : false 
    } 
); 

Online check

+0

ああ、それは私の答えと比較して巧妙なインラインです:) –

+0

答えが1つのときに私はこれを書いています。しかし、私は現在@職場ですので、ちょうど答える以外にいくつかのことがあります:) –

+1

LINQクエリのローカル変数を副作用として変更するのが好きではありません。誰かがわずかにクエリを変更すると予期しない結果が発生する可能性があります –

2

私は、ループ内でそれを割り当てるエレガントではないが、作業になります。

var mySelectedObjects = allMyObjects 
    .OrderBy(o.Date) 
    .Select(o => new ObjectType 
    { 
     Element1 = o.Element1, 
     Element2 = o.Element2, 
     Date = o.Date, 
     BooleanElement = o.BooleanElement 
    }); 

bool firstTrueFound = false; 
foreach(ObjectType o in mySelectedObjects) 
{ 
    if(o.BooleanElement) 
    { 
     if(firstTrueFound) 
      o.BooleanElement = false; 
     else 
      firstTrueFound = true; 
    } 
} 

私の心に入ってくるだけでLINQのソリューションは効率的ではありませんが、見て:

実際に私は、リスト上で動作し、 IndexOfを呼び出すことによって、ですが、それは、ランニングコストの面で二次なので、何を求めている、つまり、 Select内から項目のインデックスをチェックすることはできません(
var boolLookup = allMyObjects.ToLookup(o => o.BooleanElement); 
var mySelectedObjects = boolLookup[true] 
    .OrderBy(o => o.Date) 
    .Select((o, index) => new ObjectType 
    { 
     Element1 = o.Element1, 
     Element2 = o.Element2, 
     Date = o.Date, 
     BooleanElement = index == 0 
    }) 
    .Concat(boolLookup[false]) 
    .OrderBy(o => o.Date); 
+0

linqクエリではどうしたらいいですか? – Mafii

+0

@Mafii:どのような 'let'?クエリ構文では、select(インデックスを与えるselectのオーバーロードを使用できるメソッド構文とは対照的に)ではインデックスも取得しません。しかし、順序付けされたクエリーで 'BooleanElement'の最初の出現のインデックスが必要なので、そのインデックスは役に立ちません。 –

+0

あなたはそうだと思っていません。 – Mafii

1

それを示唆しないだろう)。ただし、selectの中には必ずしもオブジェクト作成式を記述する必要はなく、コードブロックも記述できます。このようにすれば、次のように動作します:

bool found = false; 
var mySelectedObjects = allMyObjects.OrderBy(o.Date).Select(o => 
{ 
    var booleanElement = !found && o.BooleanElement; 
    found = booleanElement; 

    var result = new ObjectType 
    { 
     Element1 = o.Element1, 
     Element2 = o.Element2, 
     Date = o.Date, 
     BooleanElement = booleanElement 
    }; 

    return result; 
}); 

これは私があなたに提供できるLINQishの方法です。これは値があるときにされて何

class TrueOnlyOnFirstAccess 
{ 
    private bool val = true; 
    private object valLock = new object(); 
    public bool Value 
    { 
     get 
     { 
      if (!val) return false; 

      lock (valLock) 
      { 
       if (!val) return false; 

       val = false; 
       return true; 
      } 
     } 
    } 
} 

だが、このようなクラスを作成してみましょう:

が@TheJPのコメントに対処するために、ここでの並列処理の問題で移動するための方法であります最初に要求された場合、最初に trueを返し、ロックコンテキスト内で値を falseに変更します。いったん値がfalseになると、それは決して変更されるべきではないので、バッキングフィールドがfalseであることが分かったら安全にfalseを返すので、不要なロックを回避できます。それを使用する方法:

TrueOnlyOnFirstAccess switcher = new TrueOnlyOnFirstAccess(); 
items.Select(item => new 
{ 
    // other props 
    BooleanElement = item.BooleanElement && switcher .Value 
}) 

ここでは、論理andの怠惰な性質を利用する - つまり、item.BooleanElement、評価する最初のものがfalseの場合、sw.Valueが呼び出されることはありません、とバッキングフィールドでなければなりません変更されません。より複雑な式では注意して使用してください。

+0

このアプローチの問題は、純粋ではない/副作用があることです。これは、たとえば並列で実行したい場合には問題を引き起こします。さもなければ、それはこれまでのところ最良の解決策です。 – TheJP

+0

もちろん、並列性は必須条件ではありません。 –

+2

これは本当にLINQではありません。選択部分はforeach内にあるはずです –

関連する問題