Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Neat way to write loop that has special logic for the first item in a collection

Tags:

c#

collections

Often I have to code a loop that needs a special case for the first item, the code never seems as clear as it should ideally be.

Short of a redesign of the C# language, what is the best way to code these loops?

// 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.
   }
}
like image 755
Ian Ringrose Avatar asked Dec 08 '10 17:12

Ian Ringrose


People also ask

Which order is correct for a for loop?

So first the condition is checked, then the loop body is executed, then the increment.

Which logic is used for looping?

To control the flow of code execution apex provides conditional statements and loops which helps us execute the code based on conditions or execute the same code repeatedly for n number of times.

How do you run a loop a certain number of times?

You can do the same type of for loop if you want to loop over every character in a string. To loop through a set of code a certain number of times, you can use the range() function, which returns a list of numbers starting from 0 to the specified end number.


2 Answers

How about:

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

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

You could turn that into an extension if you want:

public static void Do<T>(this IEnumerable<T> source, 
                         Action<T> firstItemAction,
                         Action<T> otherItemAction)
{
   // null-checks omitted

    using (var erator = source.GetEnumerator())
    {
        if (!erator.MoveNext())
            return;

        firstItemAction(erator.Current);

        while (erator.MoveNext())
           otherItemAction(erator.Current);            
    }
}
like image 117
Ani Avatar answered Oct 20 '22 05:10

Ani


You could try:

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

first / rest would look like:

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);
}

You would need to define classed FirstPart and FirstRest. FirstRest would need a run method like so (Collection, FirstAction, and RestAction are properties):

void run()
{
    bool first = true;
    foreach (var x in Collection)
    {
        if (first) {
            FirstAction(x);
            first = false;
        }
        else {
             RestAction(x);
        }
    }
}
like image 27
Scott Wisniewski Avatar answered Oct 20 '22 06:10

Scott Wisniewski