2010-12-08 11 views
12

अक्सर मुझे एक लूप को कोड करना होता है जिसमें संग्रह में पहला आइटम विशेष मामला होता है, कोड कभी स्पष्ट नहीं होता है जैसा कि यह होना चाहिए।लूप लिखने के लिए साफ तरीका है जिसमें संग्रह में पहले आइटम के लिए विशेष तर्क है

सी # भाषा का एक नया स्वरूप छोटा, इन लूप को कोड करने का सबसे अच्छा तरीका क्या है?

// this is more code to read then I would like for such a common concept 
// and it is to easy to forget to update "firstItem" 
foreach(x in yyy) 
{ 
    if (firstItem) 
    { 
    firstItem = false; 
    // other code when first item 
    } 
    // normal processing code 
} 

// this code is even harder to understand 
if (yyy.Length > 0) 
{ 
    //Process first item; 
    For(int I = 1; I <yyy.Length; i++) 
    { 
     // process the other items. 
    } 
} 
+0

मैं यहां जे स्कीट को बुला रहा हूं :) –

+3

मुझे वास्तव में कुछ भी गलत नहीं दिख रहा है (आपका पहला उदाहरण) एक बुलियन की जांच कर रहा है, जो इसे देखता है उसे जल्दी से पता चलेगा कि आप क्या कर रहे हैं। –

उत्तर

5

आप की कोशिश कर सकते:

FirstPart<T> first<T>(this IEnumerable<T> c, Action<T> a) 
{ 
    return new FirstPart<T>(c, a); 
} 

FirstRest rest<T>(this FirstPart<T> fp, Action<T> a) 
{ 
    return new FirstRest(fp.Collection, fp.Action, a); 
} 

आप होगा:

collection.first(x=> 
{ 
    //... 
}).rest(x=> 
{ 
    //... 
}).run(); 

पहले/बाकी कैसा लगेगा वर्गीकृत फर्स्टपार्ट और फर्स्टआर को परिभाषित करने की आवश्यकता है EST। FirstRest एक रन विधि की आवश्यकता होगी की तरह तो (संग्रह, FirstAction, और RestAction गुण हैं):

void run() 
{ 
    bool first = true; 
    foreach (var x in Collection) 
    { 
     if (first) { 
      FirstAction(x); 
      first = false; 
     } 
     else { 
      RestAction(x); 
     } 
    } 
} 
+2

आप सिर और पूंछ का उपयोग कर सकते हैं। अधिक कार्यात्मक होने के लिए :) –

+0

मैंने इसे चयनित उत्तर के रूप में चुना है, क्योंकि यह http://stackoverflow.com/questions/3105613/best-loop-idiom-for-special-casing-the-last-element को भी हल कर सकता है एक छोटा विस्तार –

2

जिस तरह से आपने लिखा है वह शायद सबसे साफ तरीका लिखा जा सकता है। आखिरकार, पहले तत्व के लिए विशिष्ट तर्क है, इसलिए इसे किसी भी तरह से प्रदर्शित किया जाना चाहिए।

+0

सहमत हुए। ओपीएस मूल कोड स्निपेट का दूसरा भाग सबसे स्पष्ट है। – dashton

4

मैं हर समय first परिवर्तनीय विधि का उपयोग करता हूं और यह मेरे लिए बिल्कुल सामान्य लगता है। यदि आप चाहें कि बेहतर आप LINQ First() उपयोग कर सकते हैं और Skip(1)

var firstItem = yyy.First(); 
// do the whatever on first item 

foreach (var y in yyy.Skip(1)) 
{ 
// process the rest of the collection 
} 
5

मैं LINQ का एक सा का उपयोग करने के लिए परीक्षा होगी

using System.Linq; 

var theCollectionImWorkingOn = ... 

var firstItem = theCollectionImWorkingOn.First(); 
firstItem.DoSomeWork(); 

foreach(var item in theCollectionImWorkingOn.Skip(1)) 
{ 
    item.DoSomeOtherWork(); 
} 
+0

यह वास्तव में एक लूप में 'बूल' ध्वज की जांच से बचने के लिए ओवरकिल जैसा लगता है। –

+3

'firstItem' तर्क को यह सुनिश्चित करने के लिए चेक में लपेटा जाना चाहिए कि संग्रह में कोई तत्व है ... – jball

+0

इसे पढ़ना आसान है और इसमें कम चक्रवात जटिलता है। मुझे यकीन नहीं है कि ओवरकिल कहां है। – ilivewithian

13

कैसे के बारे में:

using (var erator = enumerable.GetEnumerator()) 
{ 
    if (erator.MoveNext()) 
    { 
     ProcessFirst(erator.Current); 
     //ProcessOther(erator.Current); // Include if appropriate. 

     while (erator.MoveNext()) 
      ProcessOther(erator.Current); 
    } 
} 

आप कर सकते थे यदि आप चाहते हैं तो इसे एक एक्सटेंशन में बदलें:

पाश के लिए एक का इस्तेमाल करके आप अंतिम आइटम पर की तरह कुछ अन्य मामलों में विशेष करने की अनुमति होगी

for(int i = 0; i < yyy.Count; i++){ 
     if(i == 0){ 
      //special logic here 
     } 
} 

, में भी आइटम पर:

+3

यदि कोई व्यक्ति इस विस्तार विधि के लिए ** स्पष्ट ** नाम के साथ आ सकता है। –

+1

@ इयान, कैसे 'DoForFirstThen() 'के बारे में? –

+1

+1: मैं कहना है कि यह फोन 'ForEach', तर्क के नाम यह स्पष्ट कर चल रहा क्या है, खासकर अगर यह' था foreach (इस IEnumerable स्रोत, कार्रवाई actionForFirstItem, कार्रवाई actionForAllOtherItems) ' –

1

इस तरह के मामलों में मैं सिर्फ एक पाश के लिए इस तरह का प्रयोग करेंगे अनुक्रम, .. आदि।

0

दोनों पहले तत्व को अलग-अलग प्रोसेस करने के लिए पूरी तरह से स्वीकार्य एल्गोरिदम हैं, और वास्तव में ऐसा करने का एक अलग तरीका नहीं है।

PerformActionOnFirstElement(yyy.FirstOrDefault()); 
yyy.Skip(1).ForEach(x=>(normal processing code)); 
2

IMHO सबसे स्पष्ट तरीका है: करने की कोशिश

public static void ForEach<T>(this IEnumerable<T> elements, Action<T> firstElementAction, Action<T> standardAction) 
{ 
    var firstItem = true; 
    foreach(T element in elements) 
    { 
     if(firstItem) 
     { 
      firstItem = false; 
      firstElementAction(element) 
     } 
     else 
      standardAction(element) 
    } 
} 

... 

//usage 
yyy.ForEach(t=>(other code when first item), t=>(normal processing code)); 

Linq यह एक छोटे स्वच्छ बनाता है: इस पद्धति एक बहुत दोहराया है, तो आप इसे foreach() की एक अधिभार के पीछे छुपा सकते पहले आइटम के लिए विशेष मामलों से बचें। यह निश्चित रूप से हर स्थिति में काम नहीं कर सकता है, लेकिन "विशेष मामले" यह इंगित कर सकता है कि आपके प्रोग्राम तर्क की तुलना में अधिक जटिल है।

वैसे, मैं

if (yyy.Length > 0) 
{ 
    for(int i = 1; i <yyy.Length; i++) 
    { 
     // ... 
    } 
} 

लेकिन इसके बजाय

for(int i = 1; i <yyy.Length; i++) 
    { 
     // ... 
    } 

(जो अपने आप कैसे अनावश्यक से बचने के लिए एक विशेष मामले से निपटने का एक सरल उदाहरण है।)

+0

+1" पहले आइटम "वाक्य के लिए विशेष मामलों से बचने का प्रयास करें। – digEmAll

+1

क्या आपका यह मतलब था http://stackoverflow.com/questions/4390406/using-linq-or-otherwise-how-do-check-if-all-list-items-have-the-same-value-and-r ? यदि हां, तो आपके पूर्ण संग्रह पर सबसे अच्छा जवाब लूप जो मैंने कहा था ठीक दिखा रहा है। पहले और आराम के बजाय –

0
कोड नहीं होता

जबकि मैं व्यक्तिगत रूप से ऐसा नहीं करता, using enumerators का एक और तरीका है, जो सशर्त तर्क की आवश्यकता को कम करता है।कुछ इस तरह:

void Main() 
{ 
    var numbers = Enumerable.Range(1, 5); 
    IEnumerator num = numbers.GetEnumerator(); 

    num.MoveNext(); 
    ProcessFirstItem(num.Current); // First item 

    while(num.MoveNext()) // Iterate rest 
    { 
     Console.WriteLine(num.Current); 
    } 

} 

    void ProcessFirstItem(object first) 
    { 
     Console.WriteLine("First is: " + first); 
    } 

नमूना उत्पादन होगा:

First is: 1 
2 
3 
4 
5 
1

यहाँ एक से थोड़ा सरल विस्तार विधि है कि काम करता है। यह KeithS's solution और my answer to a related Java question का एक संयोजन है:

public static void ForEach<T>(this IEnumerable<T> elements, 
           Action<T> firstElementAction, 
           Action<T> standardAction) 
{ 
    var currentAction = firstElementAction; 
    foreach(T element in elements) 
    { 
     currentAction(element); 
     currentAction = standardAction; 
    } 
} 
0

एक अन्य विकल्प मैं के साथ आया था

enum ItemType 
{ 
    First, 
    Last, 
    Normal 
} 

list.Foreach(T item, ItemType itemType) => 
{ 
    if (itemType == ItemType.First) 
    { 
    } 

    // rest of code 
}; 

है विस्तार विधि लेखन पाठक के लिए एक व्यायाम के रूप में छोड़ दिया है ... भी चाहिए दो बूलियन झंडे " IsFirst "और" IsLast "का उपयोग ItemType enum के बजाय किया जा सकता है, या ItemType एक ऑब्जेक्ट है जिसमें" IsFirst "और" IsLast "गुण हैं?

संबंधित मुद्दे