かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

ループの最初だけ特別な処理を行いたい(追記あり)

データの配列やListがあったときに、ループを回して処理を行うことってよくありますよね。しかも、最初だけなにか特別なことをおこないたい。一般的な方法だと、ループのインデックスを見て処理するほうほうがあります。

var data = new[] { 0, 1, 2, 3, 4, 5, 6, 7 };

// ループインデックス
for (int i = 0; i < data.Length; i++)
{
    if (i == 0)
    {
        Console.WriteLine("最初にやる処理 {0}", i);
        continue;
    }

    Console.WriteLine("{0}", i);
}

まぁ特に問題はないですけど、なんとなくいつも書いててもやっとしてる処理です。あとは、foreachで回したいときとかはフラグを使ったりしますよね。

var data = new[] { 0, 1, 2, 3, 4, 5, 6, 7 };

// フラグ
bool isFirst = true;
foreach (var i in data)
{
    if (isFirst)
    {
        Console.WriteLine("最初にやる処理 {0}", i);
        isFirst = false;
        continue;
    }

    Console.WriteLine("{0}", i);
}

これらのやりかたは、別にいいんですけど何かデータのループ処理で最初の要素のためだけに分岐を入れるのはコードがちょっと複雑になりがちでいやだったんです。ということで、LINQ使ってこんな方法。

var data = new[] { 0, 1, 2, 3, 4, 5, 6, 7 };

// LINQ
if (data.Any())
{
    var first = data.First();
    Console.WriteLine("最初にやる処理 {0}", first);
    foreach (var i in data.Skip(1))
    {
        Console.WriteLine("{0}", i);
    }
}

Firstで最初の要素を取得して、最初の要素のための処理をおこなって、Skipで最初の要素をスキップして残りの要素にループを行うという方法です。Firstは、シーケンスが空だと例外が出るので、Anyをつかってコレクションが空じゃないときだけ処理するようにしています。今度から、こういう風に書こうかな。

追記:LINQの書き方のダメなところ

Any -> 処理はIEnumerableの場合遅延評価で重たい処理が走る可能性 + そのあとのループで再度重たい処理が走るという可能性があるのでNGでした。Facebookで指摘してくれたのいえさん多謝です。ということでフラグかな…。

汎用的な部品については、のいえさんが以前書かれてたので、どうしても必要な場合はこれでいいかも。

neue cc - Razorで空テンプレートとセパレータテンプレート