C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[2]: 多重ループの抜け方について


(過去ログ 173 を表示中)

[トピック内 3 記事 (1 - 3 表示)]  << 0 >>

■99773 / inTopicNo.1)  多重ループの抜け方について
  
□投稿者/ 河童 (14回)-(2022/05/28(Sat) 21:21:11)

分類:[C#] 

多重ループの抜け方について教えてください。

C# VS2022
while文、for文とswitch文で複数のループがあるときに、
値を取得した時点ですべてのループを抜ける方法がわかりません。

1. 値を取得するまでのループ(ループ1)
2.リスト1をループして値を検索(ループ2)
3.リスト1の条件に該当したとき、リスト2をループして値を検索(ループ3)
4. リスト2の条件に該当したとき、値(「20」)を取得
5.値を取得した時点ですべてのループ(ループ1)を抜けて検索を終了

switch文で該当する値が取得できたときに、
while文を終了させるため「true」を設定してますが、ループ1を抜けることができません。

値を取得した時点ですべてのループを抜けるにはどのようにすればよいですか。

よろしくお願いいたします。

 	public string Kiroku_LatestData()
        {

            string latestData = "";

            // KrkDataクラスのリストの宣言と初期化
            List<KrkData> KLst1 = new List<KrkData> {
            new KrkData { Data1 = "1"},
            new KrkData { Data1 = "2"},
            new KrkData { Data1 = "3"},
            new KrkData { Data1 = "1"},
            };
            // KrkDataクラスのリストの宣言と初期化
            List<KrkData> KLst2 = new List<KrkData> {
            new KrkData { Data1 = "10"},
            new KrkData { Data1 = "20"},
            new KrkData { Data1 = "30"},
            new KrkData { Data1 = "10"},
            };

            // KLst1にデータがない場合
            if (KLst1 == null || KLst1.Count == 0) return latestData;

            // ループ1
            // わからない事:KLst2に該当した時点でループを抜けたい
            while (true)
            {
                bool quit = false;

                // ループ2 KLst1
                for (int i = 0; i < KLst1.Count; i++)
                {
                    // 
                    if (KLst1[i].Data1 == "2") 
                    {
                        if (KLst2 != null && KLst2.Count > 0)
                        {
                            // ループ3 KLst2
                            for (int j = 0; j < KLst2.Count; j++)
                            {
                                switch (KLst2[j].Data1)
                                {
                                    case "20":
                                        latestData = KLst2[j].Data1;
                                        quit = true;
                                        break;
                                    default:
                                        break;
                                }
                            }
                        }
                    }
                }

                quit = true;

                if (quit)
                {
                    break;
                }
            }

            if (latestData != "")
            {
                latestData = "最新:" + latestData;

            }

            return latestData;
        }

引用返信 編集キー/
■99775 / inTopicNo.2)  Re[1]: 多重ループの抜け方について
□投稿者/ 魔界の仮面弁士 (3380回)-(2022/05/29(Sun) 01:46:31)
No99773 (河童 さん) に返信
> 多重ループの抜け方について教えてください。
今回の処理だと、多重ループにする必要性がまるで無いですし、
そもそも break じゃなくて return で十分ですよね…?


> while文、for文とswitch文で複数のループがあるときに、
> 値を取得した時点ですべてのループを抜ける方法がわかりません。
本当にやりたいことと、実際の例示コードの内容が乖離してはいませんか?

現状、KLst1 と KLst2 の存在はそれぞれ独立しており、相関関係があるようには見えません。
単に、それぞれのリストから特定のデータの存在チェックが行われているだけなので、
ループ処理は不要そうで、たとえば下記の 3 行で終わる処理に見えます…。

var k1 = KLst1?.Find(k => k.Data1 == "2");
var k2 = KLst2?.Find(k => k.Data1 == "20");
return (k1 == null || k2 == null) ? "" : $"最新:{k2.Data1}";

※重複データ検査が必要な場合は、Find を FindAll に変更する。


Find メソッドで十分だとは思いますが、これを LINQ に置き換えてみるとこんな感じ。
やろうと思えば 1 行で書くこともできますが、まとめすぎると読みにくいのでこの程度で。

// LINQ を使って探索してみる
if (KLst1?.Any(k => k.Data1 == "2") ?? false) {
  var lst = KLst2?.First(k => k.Data1 == "20");
  if (lst != null) {
    return $"最新:{lst.Data1}";
  }
}
return "";


もしも Find も LINQ も知らなかったのだとしても、KLst1 と KLst2 には
関係性がほぼ無いことから、必ずしもループを入れ子にする必要は無さそうです。

bool found = false;
if (KLst1 != null) {
  foreach (var k1 in KLst1) {
    if (found = (k1.Data1 == "2")) { break; }
  }
}
if (found && KLst2 != null) {
  foreach (var k2 in KLst1) {
    if (k2.Data1 == "20") {
      return "最新:" + k2.Data1;
    }
  }
}
return "";



> // KLst1にデータがない場合
> if (KLst1 == null || KLst1.Count == 0) return latestData;
事前チェックなら、
 if (KLst1 == null || KLst2 == null)
の方が良いと思いますよ。両方揃っていないと値を返せないのですから。
先にチェックしておけば、現状のループ2 とループ3 の間にある
  if (KLst2 != null && KLst2.Count > 0)
の処理を削減できるので、字下げ(インデント)を減らせますよね。


また、事前チェックの KLst1.Count == 0 ですが、これはその後の for ループのところで検査されるわけなので、
事前処理としては冗長になります。とはいえ、書いておいた方が意図が分かりやすいですね。
 if (KLst1 == null || KLst2 == null || KLst1.Count == 0 || KLst2.Count == 0)


もし、現在の実装で事前チェックするとしたら、むしろ KLst1.Count よりも KLst2.Count のチェックの方が重要です。
KLst2 が空の場合は、「KLst1 側に大量のデータ」があったとしても、ループ検査する必要が無いためです。ちなみに上記は
 if (KLst1?.Count + KLst2?.Count == 0)
のように書くこともできます。



> 1. 値を取得するまでのループ(ループ1)
まずこれが意味不明なんですよね。このループはなぜ必要だったのでしょうか?
このループが 2 回以上繰り返されるパターンが想定できませんでした。

値を取得できなかったらループを抜け出せない…というわけでも無いでしょうし。

それに「quit が true になるまで脱出できないループ」という意図ならば、
無限ループ + break 処理という組み合わせではなく、
quit 自体をループ継続条件にすれば済む話かと思います。
 
bool quit = false;
do
{
  …
} while (!quit)



> 2.リスト1をループして値を検索(ループ2)
> 3.リスト1の条件に該当したとき、リスト2をループして値を検索(ループ3)
今回の例で示したように、ループ 3 は別にループ 2 の中に置かなくても良いでしょう。

仮に入れ子にしたとしても、最初に発見したところで探索完了なわけですから、
脱出は break ではなく return になるので、多重ループであろうと関係ありません。


> switch文で該当する値が取得できたときに、
> while文を終了させるため「true」を設定してますが、ループ1を抜けることができません。
ループ1 の存在意義が意味不明である点はさておき、
quit 変数をフラグにしているのですよね?

quit を書き換えるのはループ3 だけなのですから、
quit をチェックする処理は、
ループ1 だけでなくループ2にも用意すべきでしょう。



> 値を取得した時点ですべてのループを抜けるにはどのようにすればよいですか。
VB なら、「Exit For」「Exit Do」「Exit While」のように、ループの種類ごとに
異なる脱出キーワードを持つので、入れ子のループでも一気に抜け出せるのですが、
C# の場合は、今回のようにフラグ変数を持たせることで対応してみてください。

(例外や goto を使って抜け出す方法もなくは無いですが…)
引用返信 編集キー/
■99778 / inTopicNo.3)  Re[2]: 多重ループの抜け方について
□投稿者/ 河童 (15回)-(2022/05/29(Sun) 19:13:13)
No99775 (魔界の仮面弁士 さん) に返信
そうですね。return で十分でした。
ループを全て抜けた後に文字列「最新:」を結合するのではなくて、
switch文で該当したときに結合すればよかったです。

やりたいことの説明がわかりにくくて申し訳ございませんでした。
教えていただきましたLINQを使って探索する方法でも希望通りの値を取得することができました。
コードもすっきりするので、ループ処理を変更しました。

ありがとうございました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -