Question

Y a-t-il une meilleure façon de faire cela?

string[] s = {"zero", "one", "two", "three", "four", "five"};

var x = 
s
.Select((a,i) => new {Value = a, Index = i})
.Where(b => b.Value.StartsWith("t"))
.Select(c => c.Index);

i.e. Je recherche un moyen plus efficace ou plus élégant d'obtenir les positions des éléments correspondant aux critères.

Était-ce utile?

La solution

Vous pouvez facilement ajouter votre propre méthode d'extension:

public static IEnumerable<int> IndexesWhere<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
    int index=0;
    foreach (T element in source)
    {
        if (predicate(element))
        {
            yield return index;
        }
        index++;
    }
}

Puis utilisez-le avec:

string[] s = {"zero", "one", "two", "three", "four", "five"};
var x = s.IndexesWhere(t => t.StartsWith("t"));

Autres conseils

Si vous utilisez uniquement l'exemple comme moyen d'apprendre à LINQ, ignorez ce post.

Ce n’est pas clair pour moi que LINQ est en fait le meilleur moyen de le faire. Le code ci-dessous semble plus efficace car aucun nouveau type anonyme ne doit être créé. Certes, votre exemple peut être artificiel et la technique peut être plus utile dans un contexte différent, par exemple dans une structure de données où elle pourrait tirer parti d’un index sur la valeur, mais le code ci-dessous est raisonnablement simple, compréhensible (aucune nécessaire) et sans doute plus efficace.

string[] s = {"zero", "one", "two", "three", "four", "five"};
List<int> matchingIndices = new List<int>();

for (int i = 0; i < s.Length; ++i) 
{
   if (s[i].StartWith("t"))
   {
      matchingIndices.Add(i);
   }
}

Cela me semble bien. Vous pouvez enregistrer quelques caractères en modifiant la sélection en:

.Select((Value, Index) => new {Value, Index})

Il existe également une méthode FindIndex dans la liste de collections pour laquelle vous créez une méthode de suppression pouvant renvoyer l'index de la collection. vous pouvez vous référer au lien suivant dans msdn http://msdn.microsoft.com /en-us/library/x1xzf2ca.aspx .

Comment ça? C'est similaire à l'affiche originale, mais je sélectionne d'abord les index, puis je construis une collection qui correspond aux critères.

var x = s.Select((a, i) => i).Where(i => s[i].StartsWith("t"));

C’est un peu moins efficace que certaines des autres réponses car la liste est entièrement itérée deux fois.

J'ai discuté de ce problème intéressant avec un collègue et au début, je trouvais la solution de JonSkeet excellente, mais mon collègue a souligné un problème, à savoir que si la fonction est une extension de IEnumerable<T>, elle peut être utilisée lorsqu'une collection le met en œuvre.

Avec un tableau, on peut dire que l'ordre produit avec foreach sera respecté (c.-à-d. List.ToArray itérera du premier au dernier), mais ce ne sera pas nécessairement le cas avec d'autres collections (Liste, Dictionnaire, etc), où <=> ne refléterait pas nécessairement & "ordre d'entrée &"; Pourtant, la fonction est là et peut induire en erreur.

Finalement, j'ai obtenu quelque chose de similaire à la réponse de tvanfosson, mais en tant que méthode d'extension, pour les tableaux:

public static int[] GetIndexes<T>(this T[]source, Func<T, bool> predicate)
{
    List<int> matchingIndexes = new List<int>();

    for (int i = 0; i < source.Length; ++i) 
    {
        if (predicate(source[i]))
        {
            matchingIndexes.Add(i);
        }
    }
    return matchingIndexes.ToArray();
}

Nous espérons que <=> respectera l'ordre de la dernière opération ...

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top