web-dev-qa-db-fra.com

foreach avec index

Existe-t-il un équivalent en C # de enumerate() de Python et de each_with_index de Ruby?

150
Ken

Je garde cette méthode d'extension pour cela:

public static void Each<T>(this IEnumerable<T> ie, Action<T, int> action)
{
    var i = 0;
    foreach (var e in ie) action(e, i++);
}

Et utilisez-le comme ceci:

var strings = new List<string>();
strings.Each((str, n) =>
{
    // hooray
});

Ou pour permettre un comportement de type break-:

public static bool Each<T>(this IEnumerable<T> ie, Func<T, int, bool> action)
{
    int i = 0;
    foreach (T e in ie) if (!action(e, i++)) return false;
    return true;
}

var strings = new List<string>() { "a", "b", "c" };

bool iteratedAll = strings.Each ((str, n)) =>
{
    if (str == "b") return false;
    return true;
});
258
Dan

Vous pouvez faire ce qui suit

foreach (var it in someCollection.Select((x, i) => new { Value = x, Index = i }) )
{
   if (it.Index > SomeNumber) //      
}

Cela créera une valeur de type anonyme pour chaque entrée de la collecte. Il aura deux propriétés

  1. Valeur: avec la valeur d'origine de la collection
  2. Index: avec l'index dans la collection
199
JaredPar

Le C # foreach n'a pas d'index intégré. Vous devrez ajouter un entier en dehors de la boucle foreach et l'incrémenter à chaque fois.

int i = -1;
foreach (Widget w in widgets)
{
   i++;
   // do something
}

Vous pouvez également utiliser une boucle standard comme suit:

for (int i = 0; i < widgets.Length; i++)
{
   w = widgets[i];
   // do something
}
59
David Morton

J'aime pouvoir utiliser foreach, alors j'ai créé une méthode d'extension et une structure:

public struct EnumeratedInstance<T>
{
    public long cnt;
    public T item;
}

public static IEnumerable<EnumeratedInstance<T>> Enumerate<T>(this IEnumerable<T> collection)
{
    long counter = 0;
    foreach (var item in collection)
    {
        yield return new EnumeratedInstance<T>
        {
            cnt = counter,
            item = item
        };
        counter++;
    }
}

et un exemple d'utilisation:

foreach (var ii in new string[] { "a", "b", "c" }.Enumerate())
{
    Console.WriteLine(ii.item + ii.cnt);
}

Une bonne chose est que si vous êtes habitué à la syntaxe Python, vous pouvez toujours l'utiliser:

foreach (var ii in Enumerate(new string[] { "a", "b", "c" }))
16
Daniel K

En plus des réponses LINQ déjà données, j'ai une classe "SmartEnumerable" qui vous permet d'obtenir l'index et le "premier/dernier". C'est un peu moche en termes de syntaxe, mais vous le trouverez peut-être utile.

Nous pouvons probablement améliorer l'inférence de type en utilisant une méthode statique dans un type non générique, et le typage implicite aidera également.

15
Jon Skeet

Ma solution implique une classe Pair simple que j'ai créée pour un usage général et qui, sur le plan opérationnel, est essentiellement identique à la classe d'infrastructure KeyValuePair. Ensuite, j'ai créé un couple de fonctions d'extension pour IEnumerable appelé Ordinate (à partir du terme de théorie des ensembles " ordinal ").

Ces fonctions renverront pour chaque élément un objet Pair contenant l'index et l'élément lui-même.

public static IEnumerable<Pair<Int32, X>> Ordinate<X>(this IEnumerable<X> lhs)
{
    return lhs.Ordinate(0);
}

public static IEnumerable<Pair<Int32, X>> Ordinate<X>(this IEnumerable<X> lhs, Int32 initial)
{
    Int32 index = initial - 1;

    return lhs.Select(x => new Pair<Int32, X>(++index, x));
}
6
Chris Ammerman

Non, il n'y en a pas.

Comme d'autres personnes l'ont montré, il existe des moyens de simuler le comportement de Ruby. Mais il est possible d'avoir un type qui implémente IEnumerable qui n'expose pas un index.

3
Darryl Braaten

Ceci est votre collection

var values = new[] {6, 2, 8, 45, 9, 3, 0};

Faire une plage d'index pour cette collection

var indexes = Enumerable.Range(0, values.Length).ToList();

Utilisez la plage pour itérer avec index

indexes.ForEach(i => values[i] += i);
indexes.ForEach(i => Console.Write("[{0}] = {1}", i, values[i]));
1
vonWippersnap

Je viens de trouver une solution intéressante:

public class DepthAware<T> : IEnumerable<T>
{
    private readonly IEnumerable<T> source;

    public DepthAware(IEnumerable<T> source)
    {
        this.source = source;
        this.Depth = 0;
    }

    public int Depth { get; private set; }

    private IEnumerable<T> GetItems()
    {
        foreach (var item in source)
        {
            yield return item;
            ++this.Depth;
        }
    }

    public IEnumerator<T> GetEnumerator()
    {
        return GetItems().GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

// Generic type leverage and extension invoking
public static class DepthAware
{
    public static DepthAware<T> AsDepthAware<T>(this IEnumerable<T> source)
    {
        return new DepthAware<T>(source);
    }

    public static DepthAware<T> New<T>(IEnumerable<T> source)
    {
        return new DepthAware<T>(source);
    }
}

Usage:

var chars = new[] {'a', 'b', 'c', 'd', 'e', 'f', 'g'}.AsDepthAware();

foreach (var item in chars)
{
    Console.WriteLine("Char: {0}, depth: {1}", item, chars.Depth);
}
1
Pz.

Cela dépend de la classe que vous utilisez.

Dictionary <(Of <(TKey, TValue>)>) Classe pour l'exemple prend en charge cette

La classe générique Dictionary <(Of <(TKey, TValue>)>) fournit un mappage d'un ensemble de clés à un ensemble de valeurs.

Aux fins de l'énumération, chaque élément du dictionnaire est traité comme une structure KeyValuePair <(Of <(TKey, TValue>)>) représentant une valeur et sa clé. L'ordre dans lequel les articles sont retournés est indéfini.

foreach (KeyValuePair kvp dans myDictionary) {...}

0
VBNight