17

5 レベルまたは 6 レベルの深さのオブジェクトの 1 つ以上のプロパティでデータ メンバーを変更する必要があるとします。

検査と変更が必要なプロパティに到達するために反復する必要があるサブコレクションがあります。

ここでは、Employee の住所を消去するメソッドを呼び出しています。ループ内でデータを変更しているため、現在の実装でforは例外を防ぐためにループが必要です。

「foreach 反復変数」であるため、「someVariable」に代入できません

ネストされた と を使用した現在のアルゴリズム (難読化) を次に示しforeachますfor

foreach (var emp in company.internalData.Emps)
{
    foreach (var addr in emp.privateData.Addresses)
    {
        int numberAddresses = addr.Items.Length;

        for (int i = 0; i < numberAddresses; i++)
        {
            //transform this street address via a static method
            if (addr.Items[i].Type =="StreetAddress")
               addr.Items[i].Text = CleanStreetAddressLine(addr.Items[i].Text);
        }
    }
}

質問: このアルゴリズムは、LINQ を使用して再実装できますか? 要件は、元のコレクションのデータがその静的メソッド呼び出しによって変更されることです。

更新: jQuery/selector タイプのソリューションの方向性を考えていました。私はこの質問をそのように具体的に言いませんでした。私はその考えに行き過ぎていたことに気づきました(副作用はありません)。みんなありがとう!jQueryのようなセレクターを実行する方法があれば、それを見てみましょう!

4

9 に答える 9

21
foreach(var item in company.internalData.Emps
                        .SelectMany(emp => emp.privateData.Addresses)
                        .SelectMany(addr => addr.Items)
                        .Where(addr => addr.Type == "StreetAddress"))
     item.Text = CleanStreetAddressLine(item.Text);
于 2009-08-26T17:04:43.123 に答える
14
var dirtyAddresses = company.internalData.Emps.SelectMany( x => x.privateData.Addresses )
                                              .SelectMany(y => y.Items)
                                              .Where( z => z.Type == "StreetAddress");

  foreach(var addr in dirtyAddresses)
    addr.Text = CleanStreetAddressLine(addr.Text);
于 2009-08-26T17:07:41.433 に答える
12

LINQ は、オブジェクトのセットを変更するためのものではありません。SELECT sql ステートメントが選択されている行の値を変更するとは思わないでしょうか? LINQ が何を表しているかを覚えておくと役立ちます。Language IN tegrated Q ueryです。linqクエリ内でオブジェクトを変更することは、私見ではアンチパターンです。

Stan R.の答えは、 foreachループを使用したより良い解決策だと思います。

于 2009-08-26T17:09:30.993 に答える
10

「クエリ内包表記」構文とドット付きメソッド呼び出し構文を同じステートメントに混在させるのは好きではありません。

クエリアクションから分離するというアイデアは気に入っています。これらは意味的に異なるため、多くの場合、コード内でそれらを分離することは理にかなっています。

var addrItemQuery = from emp in company.internalData.Emps
                    from addr in emp.privateData.Addresses
                    from addrItem in addr.Items
                    where addrItem.Type == "StreetAddress"
                    select addrItem;

foreach (var addrItem in addrItemQuery)
{
    addrItem.Text = CleanStreetAddressLine(addrItem.Text);
}

コードに関するいくつかのスタイル ノート。これらは個人的なものであるため、同意できない場合があります。

  • 一般的に、略語は避けます ( Empsempaddr)
  • 一貫性のない名前はより混乱を招きます ( addrvs. Addresses): 1 つを選択して、それを使い続ける
  • 「数」という言葉はあいまいです。ID (「囚人番号 378、前に出てください。」) またはカウント (「そのフィールドの羊の数は 12 です。」) のいずれかです。コードで両方の概念を頻繁に使用するため、これを明確にすることは重要です。私はしばしば最初のものに「インデックス」を使用し、2番目に「カウント」を使用します。
  • フィールドをtype文字列にするのはコードの匂いです。あなたがそれを作ることができれば、enumあなたのコードはおそらく良くなるでしょう。
于 2009-08-26T17:34:48.150 に答える
2

汚れたワンライナー。

company.internalData.Emps.SelectMany(x => x.privateData.Addresses)
    .SelectMany(x => x.Items)
    .Where(x => x.Type == "StreetAddress")
    .Select(x => { x.Text = CleanStreetAddressLine(x.Text); return x; });
于 2009-08-26T17:49:22.737 に答える
1

LINQ は、副作用を持つオプションを提供しません。ただし、次のことができます。

company.internalData.Emps.SelectMany(emp => emp.Addresses).SelectMany(addr => Addr.Items).ToList().ForEach(/*either make an anonymous method or refactor your side effect code out to a method on its own*/);
于 2009-08-26T17:04:49.927 に答える
1

あなたはこれを行うことができますが、あなたは本当にしたくありません. 何人かのブロガーが Linq の機能的性質について語っています。MS が提供するすべての Linq メソッドを見ると、それらが副作用を引き起こさないことがわかります。これらは戻り値を生成しますが、それ以外は何も変更しません。Linq の ForEach メソッドで引数を検索すると、この概念の適切な説明が得られます。

それを念頭に置いて、おそらくあなたが望むのは次のようなものです:

var addressItems = company.internalData.Emps.SelectMany(
    emp => emp.privateData.Addresses.SelectMany(
           addr => addr.Items
    )
);
foreach (var item in addressItems)
{
   ...
}

ただし、要求したことを正確に実行したい場合は、次の方向に進む必要があります。

var addressItems = company.internalData.Emps.SelectMany(
    emp => emp.privateData.Addresses.SelectMany(
           addr => addr.Items.Select(item =>
           { 
              // Do the stuff
              return item;
           }) 
    )
);
于 2009-08-26T17:10:23.957 に答える
0

FOREACH ループを使用して LINQ の結果を更新するには、まずローカルの「リスト」変数を作成し、次に FOREACH ループを使用して更新を実行します。このように値が更新されます。ここでもっと読む:

FOREACH ループを使用して LINQ 結果の値を更新する方法

于 2012-04-19T14:44:46.557 に答える