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;
    }
}
initialZero
fuente
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

Sidney.andrews
fuente
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;
Paolo Moretti
fuente
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();
Jonas Bötel
fuente
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();
Oso pardo
fuente
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);

fuente
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
2

Acabo de publicar mi implementación del método de extensión IndexWhere () (con pruebas unitarias):

http://snipplr.com/view/53625/linq-index-of-item--indexwhere/

Uso de ejemplo:

int index = myList.IndexWhere(item => item.Something == someOtherThing);
joelsand
fuente
No usaría esa biblioteca, no implementa esos métodos correctamente. Ignora la eliminación.
Yuriy Faktorovich
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.

Roshna Omer
fuente
0
int index = -1;
index = words.Any (word => { index++; return word.IsKey; }) ? index : -1;
Marcel Valdez Orozco
fuente