c# - while - foreach avec liste générique, détection de la première itération lors de l'utilisation du type de valeur




while c# (6)

Au lieu de if (i == ints.First()) , cela fonctionne-t-il si vous utilisez if (i.Equals(ints.First()) ?

Lorsque je passe une liste générique, je veux souvent faire quelque chose de différent pour le premier élément de la liste:

List<object> objs = new List<object>
{
    new Object(),
    new Object(),
    new Object(),
    new Object()
};

foreach (object o in objs)
{
    if (o == objs.First())
    {
        System.Diagnostics.Debug.WriteLine("First object - do something special");
    }
    else
    {
        System.Diagnostics.Debug.WriteLine("object Do something else");
    }
}

Cela va produire:

    First object - do something special
    object Do something else
    object Do something else
    object Do something else

Tout cela est bien et dandy.

Cependant, si ma liste générique est de type valeur, cette approche échouera.

List<int> ints = new List<int> { 0, 0, 0, 0 };
foreach (int i in ints)
{
    if (i == ints.First())
    {
        System.Diagnostics.Debug.WriteLine("First int - do something special");
    }
    else
    {
        System.Diagnostics.Debug.WriteLine("int Do something else");
    }
}

Cela va produire:

    First int - do something special
    First int - do something special
    First int - do something special
    First int - do something special

Maintenant je sais que je pourrais recoder ceci pour ajouter une variable boolean ou traditionnelle for boucle, mais je me demande s'il y a moyen de savoir si une boucle foreach est sur la première itération de sa boucle.


Eh bien, vous pourriez le coder en utilisant l'itération explicite:

using(var iter = ints.GetEnumerator()) {
  if(iter.MoveNext()) {
     // do "first" with iter.Current

     while(iter.MoveNext()) {
       // do something with the rest of the data with iter.Current
     }
  }
}

L'option bool flag (avec foreach ) est probablement plus facile si ... c'est ce que je fais (presque) toujours!

Une autre option serait LINQ:

if(ints.Any()) {
  var first = ints.First();
  // do something with first
}

foreach(var item in ints.Skip(1)) {
  // do something with the rest of them
}

L'inconvénient de ce qui précède est qu'il essaie de regarder la liste 3 fois ... puisque nous savons que c'est une liste, c'est bien - mais si tout ce que nous avions était un IEnumerable<T> , il ne serait que sensé d'itérer une fois (puisque la source pourrait ne pas être re-lisible).


Le problème que vous avez est parce que l'égalité pour les types de valeur est basée sur la valeur réelle, pas la référence elle-même. Plus précisément, dans votre exemple, votre liste contient tous des zéros, donc il est demandé si currentItem == firstItem, et comme ils sont tous deux à zéro, c'est toujours vrai. Pour ce genre de chose, j'ai toujours utilisé un drapeau booléen.


Puisque vous utilisez déjà LINQ, vous pouvez le faire:

var list = new List<Int32>();

// do something with list.First();

foreach (var item in list.Skip(1))
{
    // do other stuff
}

foreach(int i in ints.Take(1))
{
 //do first thing
}

foreach(int i in ints.Skip(1))
{
  //do other things
}

Modification à partir d'une autre réponse:

IList<object> objs = new List<object>
{
    new Object(),
    new Object(),
    new Object(),
    new Object()
};

// to access first element: objs[0]
// to access last element: objs[objs.Count - 1]

System.Diagnostics.Debug.WriteLine("First object - do something special");

foreach (object o in objs.Skip(1))
{
    System.Diagnostics.Debug.WriteLine("object Do something else");
}

Lien de référence sur:

Utilisation de Skip : Méthode Enumerable.Skip (IEnumerable, Int32)

Utilisation de IList<T> : List ou IList





.net