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

后端 未结 12 2578
忘了有多久
忘了有多久 2021-02-13 17:31

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,

相关标签:
12条回答
  • 2021-02-13 17:35

    I'd be tempted to use a bit of linq

    using System.Linq;
    
    var theCollectionImWorkingOn = ...
    
    var firstItem = theCollectionImWorkingOn.First();
    firstItem.DoSomeWork();
    
    foreach(var item in theCollectionImWorkingOn.Skip(1))
    {
        item.DoSomeOtherWork();
    }
    
    0 讨论(0)
  • 2021-02-13 17:36

    In cases like this I would just use a for loop like this:

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

    Using a for loop also would allow you to do something special in other cases like on the last item, on even items in the sequence, ..etc.

    0 讨论(0)
  • 2021-02-13 17:37

    My solution:

    foreach (var x in yyy.Select((o, i) => new { Object = o, Index = i } )
    {
      if (x.Index == 0)
      {
        // First item logic
      }
      else
      {
        // Rest of items
      }
    }
    
    0 讨论(0)
  • 2021-02-13 17:39

    Here's a slightly simpler extension method that does the job. This is a combination of KeithS's solution and 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 讨论(0)
  • 2021-02-13 17:39

    Another option I came up with is

    enum ItemType
    {
      First,
      Last,
      Normal
    }
    
    list.Foreach(T item, ItemType itemType) =>
    {
       if (itemType == ItemType.First)
       {
       }
    
       // rest of code
    };
    

    Writing the extension method is left as an exercise for the reader… Also should two Boolean flags “IsFirst” and “IsLast” be used instead of ItemType enum, or ItemType be an object that has “IsFirst” and “IsLast” properties?

    0 讨论(0)
  • 2021-02-13 17:39

    Both of those are perfectly acceptable algorithms for processing the first element differently, and there really isn't a different way to do it. If this pattern is repeated a lot, you could hide it behind an overload of ForEach():

    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 makes it a little cleaner:

    PerformActionOnFirstElement(yyy.FirstOrDefault());
    yyy.Skip(1).ForEach(x=>(normal processing code));
    
    0 讨论(0)
提交回复
热议问题