Pregunta

¿Hay una mejor manera de hacer esto?

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

es decir Estoy buscando una forma más eficiente o más elegante de obtener las posiciones de los artículos que coincidan con los criterios.

¿Fue útil?

Solución

Puede agregar fácilmente su propio método de extensión:

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

Luego úsalo con:

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

Otros consejos

Si solo está usando el ejemplo como una forma de aprender LINQ, ignore esta publicación.


No está claro para mí que LINQ sea realmente la mejor manera de hacer esto. El siguiente código parece que sería más eficiente ya que no es necesario crear ningún tipo anónimo nuevo. De acuerdo, su ejemplo puede ser inventado y la técnica podría ser más útil en un contexto diferente, por ejemplo, en una estructura de datos donde podría aprovechar un índice de valor, pero el código a continuación es razonablemente sencillo, comprensible (sin pensarlo) requerido) y posiblemente más eficiente.

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

Me parece bien. Puede guardar un par de caracteres cambiando la selección a:

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

También hay un método FindIndex en la Lista de colecciones para el que crea un método de eliminación que puede devolver el índice de la colección. puede consultar el siguiente enlace en msdn http://msdn.microsoft.com /en-us/library/x1xzf2ca.aspx .

¿Qué tal esto? Es similar a los pósters originales, pero primero selecciono los índices y luego construyo una colección que coincide con los criterios.

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

Esto es un poco menos eficiente que algunas de las otras respuestas, ya que la lista se repite por completo dos veces.

Discutí este interesante problema con un colega y al principio pensé que la solución de JonSkeet era excelente, pero mi colega señaló un problema, a saber, que si la función es una extensión de IEnumerable<T>, entonces puede usarse donde una colección lo implementa.

Con una matriz, es seguro decir que se respetará el orden producido con foreach (es decir, List.ToArray iterará del primero al último), pero no necesariamente sería el caso con otras colecciones (Lista, Diccionario, etc), donde <=> no reflejaría necesariamente " orden de entrada " ;. Sin embargo, la función está ahí y puede ser engañosa.

Al final, terminé con algo similar a la respuesta de tvanfosson, pero como método de extensión, para matrices:

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

Esperamos que <=> respete el orden de la última operación ...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top