かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

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

データの配列や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で空テンプレートとセパレータテンプレート