Encuentra el índice de un valor en una matriz


113

¿Se puede usar linq de alguna manera para encontrar el índice de un valor en una matriz?

Por ejemplo, este bucle ubica el índice de clave dentro de una matriz.

for (int i = 0; i < words.Length; i++)
{
    if (words[i].IsKey)
    {
        keyIndex = i;
    }
}

En realidad, solo conseguir la palabra también estaría bien.
initialZero

Respuestas:


183
int keyIndex = Array.FindIndex(words, w => w.IsKey);

Eso en realidad le da el índice entero y no el objeto, independientemente de la clase personalizada que haya creado


1
¿Por qué no se convirtió en un método de extensión de forma System.Linqpredeterminada? ¡Ahí es donde está todo lo demás como esto!
qJake

63

Para matrices puede utilizar Array.FindIndex<T>:

int keyIndex = Array.FindIndex(words, w => w.IsKey);

Para las listas puede utilizar List<T>.FindIndex:

int keyIndex = words.FindIndex(w => w.IsKey);

También puede escribir un método de extensión genérico que funcione para cualquier Enumerable<T>:

///<summary>Finds the index of the first item matching an expression in an enumerable.</summary>
///<param name="items">The enumerable to search.</param>
///<param name="predicate">The expression to test the items against.</param>
///<returns>The index of the first matching item, or -1 if no items match.</returns>
public static int FindIndex<T>(this IEnumerable<T> items, Func<T, bool> predicate) {
    if (items == null) throw new ArgumentNullException("items");
    if (predicate == null) throw new ArgumentNullException("predicate");

    int retVal = 0;
    foreach (var item in items) {
        if (predicate(item)) return retVal;
        retVal++;
    }
    return -1;
}

Y también puedes usar LINQ:

int keyIndex = words
    .Select((v, i) => new {Word = v, Index = i})
    .FirstOrDefault(x => x.Word.IsKey)?.Index ?? -1;

2
También hay un método List (T) .FindIndex
tdc

@Paolo ¿qué tal una lista que se genera a partir de Lambda? Recibo un error de predicado.
Mihir Patel

10
int keyIndex = words.TakeWhile(w => !w.IsKey).Count();

3
+1 pero, ¿y si el elemento no existe? obtendremos 0, pero el índice es -1
Arsen Mkrtchyan

@ArsenMkrtchyan Si el artículo no existe, esto produce palabras
Jim Balter

@ArsenMkrtchyan Escribiste "obtendremos 0" ... eso estaba mal. Escribiste "pero el índice es -1" ... eso también está mal. -1 es un indicador común de falla, pero no es el único posible. Cualquier valor que no esté dentro de 0..words.Length-1 será suficiente.
Jim Balter

1
@JimBalter, quiero decir, si el elemento no existe, la expresión devolverá 0, ¿qué hay de malo en él? Estoy de acuerdo en que -1 es un indicador común, pero estoy de acuerdo en que es obvio que el 99% de los casos -1 es el valor esperado cuando el elemento no existe. al menos 0 es incorrecto cuando el elemento no existe
Arsen Mkrtchyan

7

Si quieres encontrar la palabra puedes usar

var word = words.Where(item => item.IsKey).First();

Esto le da el primer elemento para el que IsKey es verdadero (si no es posible, es posible que desee usar .FirstOrDefault()

Para obtener tanto el elemento como el índice, puede usar

KeyValuePair<WordType, int> word = words.Select((item, index) => new KeyValuePair<WordType, int>(item, index)).Where(item => item.Key.IsKey).First();

linq está loco. Pensé que los genéricos de Java eran una locura. De todos modos, gracias por toda la ayuda.
initialZero

¿Es una práctica aceptada emitir el valor de retorno o hay alguna manera de definir el tipo de palabra?
initialZero

ok, se me ocurrió esto. DecodedMessageWord keyWord = palabras.Where (x => x.IsKey == true) .First <DecodedMessageWord> ();
initialZero

5
@initialZero revisa las sobrecargas First, se necesita un predicado, no necesitas el Where.
Yuriy Faktorovich

3

Prueba esto...

var key = words.Where(x => x.IsKey == true);

2
Esta parece una solución muy débil en comparación con las respuestas de Grizzly y masenkablast. masenkablast responde la pregunta original y Grizzly ofrece una mejor solución para encontrar la palabra, ya que su "var" final será la palabra real y no un IEnumerable <TSource> que contiene 1 palabra.
James


1

Esta solución me ayudó más, de msdn microsoft :

var result =  query.AsEnumerable().Select((x, index) =>
              new { index,x.Id,x.FirstName});

queryes tu toList()consulta.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.