2011-07-01 5 views
7

最初のIEnumerableアイテムを別のものとは異なる方法で処理する最も洗練された方法は、各繰り返しでテストする必要はありません。最初のIEnumerableアイテムを別の方法で処理する最もエレガントな方法

各反復のテストで、それは次のようになります。

// "first item done" flag 
bool firstDone = false; 

// items is an IEnumerable<something> 
foreach (var item in items) 
{ 
    if (!firstDone) 
    { 
     // do this only once 
     ProcessDifferently(item); 
     firstDone = true; 
     continue; 
    } 

    ProcessNormally(item); 
} 

私はこれを行う場合:

ProcessDifferently(items.First()); 
ProcessNormally(items.Skip(1)); // this calls `items.GetEnumerator` again 

を、それは私が(避けたいた、二回GetEnumeratorを起動しますLinq-to-SQLの場合など)。

コードを何回か実行する必要がある場合はどうすればよいですか?

public void Process<T>(IEnumerable<T> source, 
         Action<T> firstAction, 
         Action<T> remainderAction) 
{ 
    // TODO: Argument validation 
    using (var iterator = source.GetEnumerator()) 
    { 
     if (iterator.MoveNext()) 
     { 
      firstAction(iterator.Current); 
     } 
     while (iterator.MoveNext()) 
     { 
      remainderAction(iterator.Current); 
     } 
    } 
} 

として呼び出されます:私はいくつかの場所でそれを行うために必要な場合

答えて

12

、私はこの方法を抽出したい

Process(items, ProcessDifferently, ProcessNormally); 

他のオプションがあまりにもありますが、それは本当にに依存するであろう状況。

+0

ありがとうございます。きれいで清潔です。私が尋ねたことを正確に行います。 – dilbert

0

あなたはそれを昔ながらの方法行うことができます。

private static void Main(string[] args) 
    { 
     var testdata = new[] { "a", "b", "c", "d", "e" }; 

     var action = FirstThenRest<string>(
      s => Console.WriteLine("First: " + s), 
      s => Console.WriteLine("Rest: " + s)); 

     foreach (var s in testdata) 
      action(s); 
    } 

    public static Action<T> FirstThenRest<T>(Action<T> first, Action<T> rest) 
    { 
     Action<T> closure = t => 
          { 
           first(t); 
           closure = rest; 
          }; 

     return t => closure(t); 
    } 

この出力:

First: a 
Rest: b 
Rest: c 
Rest: d 
Rest: e 

ない条件文

var itemsList = items.ToList(); 
ProcessDifferently(itemsList[0]); 

for(int i=1;i<itemsList.Count;i++) 
{ 
    ProcessNormally(itemsList[i]); 
} 
+0

これはリストと配列に対して機能しますが、IEnumerableに対して同じことを2度反復することなく行う必要があります。 – dilbert

+0

ああ、あなたは正しい。わかりやすくするためにコード例を変更しました。骨組みの解答 - とても素敵なところに行ってください。 – HitLikeAHammer

1

をここでもう一つの方法です。 :D

編集: "ヘッド"と "テール"はおそらくより良い用語ですが、私は今それを変更するにはあまりにも怠惰です。

関連する問題