2009-07-24 8 views
169

Aquí tengo un ejemplo simple para encontrar un elemento en una lista de cadenas. Normalmente uso para el bucle o delegado anónimo para hacerlo así:¿Encontrar un artículo en la lista de LINQ?

int GetItemIndex(string search) 
{ 
    int found = -1; 
    if (_list != null) 
    { 
    foreach (string item in _list) // _list is an instance of List<string> 
    { 
     found++; 
     if (string.Equals(search, item)) 
     { 
      break; 
     } 
     } 
     /* use anonymous delegate 
     string foundItem = _list.Find(delegate(string item) { 
     found++; 
     return string.Equals(search, item); 
     }); 
     */ 
    } 
    return found; 
} 

LINQ es nuevo para mí. Tengo curiosidad si puedo usar LINQ para encontrar un elemento en la lista. ¿Cómo es posible?

+0

Eso es grande. Sin embargo, esos son todos estilos de expresión lamda. Yo uso una lista simple aquí. La lista puede ser una clase con varias propiedades y algunas se usan para búsqueda. Entonces, cualquier forma de LINQ para buscar como "de ... en ... donde ... seleccionar ..." –

+0

Nah, lo siento. La mayoría de estos métodos (Primero, Único, Cualquiera, ...) no se pueden * traducir * directamente a ese formulario. –

+0

No importa, de hecho puede deshacerse de las lambdas por algunos casos ... –

Respuesta

364

Hay algunas maneras (tenga en cuenta que esto es no una lista completa).

1) Single devolverá un resultado único, pero será una excepción si no encuentra ninguno o más de uno (que puede o no ser lo que quiere):

string search = "lookforme"; 
List<string> myList = new List<string>(); 
string result = myList.Single(s => s == search); 

Nota SingleOrDefault() se comportará el lo mismo, excepto que devolverá nulo para los tipos de referencia, o el valor predeterminado para los tipos de valores, en lugar de arrojar una excepción.

2) Where devolverá todos los elementos que coincidan con sus criterios, por lo que puede conseguir un IEnumerable con un elemento:

IEnumerable<string> results = myList.Where(s => s == search); 

3) First devolverá el primer elemento que coincide con su búsqueda:

string result = myList.First(s => s == search); 

La nota FirstOrDefault() se comportará igual, excepto que devolverá nulo para los tipos de referencia, o el valor predeterminado para los tipos de valores, en lugar de arrojar una excepción.

+30

Gran respuesta.Encontré que SingleOrDefault es mi respuesta preferida, igual que Single, pero devuelve 'null' si no puede encontrarla. –

+2

No sabía Single() o SingleOrDefault(). Muy útil. – draconis

+0

¿Se pueden usar estos métodos con otras colecciones como 'ReadOnlyCollection' o' ObservableCollection'? – yellavon

65

Si desea que el índice del elemento, esto lo hará:

int index = list.Select((item, i) => new { Item = item, Index = i }) 
       .First(x => x.Item == search).Index; 

// or 
var tagged = list.Select((item, i) => new { Item = item, Index = i }); 
int index = (from pair in tagged 
      where pair.Item == search 
      select pair.Index).First(); 

Usted no puede deshacerse de la lambda en el primer pase.

Tenga en cuenta que esto arrojará si el artículo no existe. Esto resuelve el problema recurriendo a enteros con valores nulos:

var tagged = list.Select((item, i) => new { Item = item, Index = (int?)i }); 
int? index = (from pair in tagged 
      where pair.Item == search 
      select pair.Index).FirstOrDefault(); 

Si usted quiere el artículo:

// Throws if not found 
var item = list.First(item => item == search); 
// or 
var item = (from item in list 
      where item == search 
      select item).First(); 

// Null if not found 
var item = list.FirstOrDefault(item => item == search); 
// or 
var item = (from item in list 
      where item == search 
      select item).FirstOrDefault(); 

Si desea contar el número de elementos que coinciden con:

int count = list.Count(item => item == search); 
// or 
int count = (from item in list 
      where item == search 
      select item).Count(); 

Si desea todos los elementos que coinciden:

var items = list.Where(item => item == search); 
// or 
var items = from item in list 
      where item == search 
      select item; 

Y no olvide verificar la lista para null en cualquiera de estos casos.

O use (list ?? Enumerable.Empty<string>()) en lugar de list.

Gracias a Pavel por ayudar en los comentarios.

+2

Dos puntos. Primero, no hay una necesidad real de usar 'string.Equals' aquí - nada está mal con' == '. En segundo lugar, también mencionaría 'FirstOrDefault' (para los casos en que el elemento podría no estar allí), y' Seleccionar' con índice para cubrir el caso donde se necesita el índice del artículo (como está en la muestra en la pregunta). –

+0

Gracias por señalarlos. –

+0

No estoy contento todavía. No hay un índice -1 (no encontrado) en mi ejemplo. ¿Cualquier sugerencia? –

12

Si realmente es un List<string> que no es necesario LINQ, sólo tiene que utilizar:

int GetItemIndex(string search) 
{ 
    return _list == null ? -1 : _list.IndexOf(search); 
} 

Si usted está buscando el artículo en sí mismo, trate de:

string GetItem(string search) 
{ 
    return _list == null ? null : _list.FirstOrDefault(s => s.Equals(search)); 
} 
+1

Siguiendo la lógica del primer ejemplo, podríamos usar '_list.Find (búsqueda)' para el segundo. – jwg

9

¿Quieres que el elemento en la lista o el elemento real en sí (asumiría el elemento en sí).

Aquí hay un montón de opciones para usted:

string result = _list.First(s => s == search); 

string result = (from s in _list 
       where s == search 
       select s).Single(); 

string result = _list.Find(search); 

int result = _list.IndexOf(search); 
+0

Whoa ... algunas personas son súper rápidas uno el gatillo;) – Kelsey

+0

¿qué tal el índice como valor de retorno? –

+0

y ¿tengo que comprobar si _list es nulo en la forma de desde ... en _list ...? –

2

Solía ​​usar un diccionario, que es una especie de una lista indexada que me dará exactamente lo que quiero cuando lo quiero.

Dictionary<string, int> margins = new Dictionary<string, int>(); 
margins.Add("left", 10); 
margins.Add("right", 10); 
margins.Add("top", 20); 
margins.Add("bottom", 30); 

cuando lo desee acceder a mis valores márgenes, por ejemplo, os expreso mi diccionario:

int xStartPos = margins["left"]; 
int xLimitPos = margins["right"]; 
int yStartPos = margins["top"]; 
int yLimitPos = margins["bottom"]; 

Por lo tanto, dependiendo de lo que está haciendo, un diccionario puede ser útil.

+0

Gran respuesta a una pregunta diferente. – jwg

6

Este método es más fácil y más seguro

var lOrders = new List<string>(); 

bool insertOrderNew = lOrders.Find(r => r == "1234") == null ? true : false

+1

Creo que ni siquiera necesitamos 'true: false' a continuación debería funcionar igual ' bool insertOrderNew = lOrders.Find (r => r == "1234") == null; ' – Vbp

5

¿Qué tal IndexOf?

Busca el objeto especificado y devuelve el índice de la primera aparición en la lista

Por ejemplo

> var boys = new List<string>{"Harry", "Ron", "Neville"}; 
> boys.IndexOf("Neville") 
2 
> boys[2] == "Neville" 
True 

Observe que devuelve -1 si no se produce el valor en la lista

> boys.IndexOf("Hermione") 
-1 
2

Aquí hay una manera de reescribir su método para usar L INQ:

public static int GetItemIndex(string search) 
{ 
    List<string> _list = new List<string>() { "one", "two", "three" }; 

    var result = _list.Select((Value, Index) => new { Value, Index }) 
      .SingleOrDefault(l => l.Value == search); 

    return result == null ? -1 : result.Index; 
} 

Por lo tanto, llamándola con

GetItemIndex("two") regresará 1,

y

GetItemIndex("notthere") volverá -1.

Referencia: linqsamples.com

1

probar este código:

return context.EntitytableName.AsEnumerable().Find(p => p.LoginID.Equals(loginID) && p.Password.Equals(password)).Select(p => new ModelTableName{ FirstName = p.FirstName, UserID = p.UserID }); 
1

Esto le ayudará a conseguir la primera o por defecto el valor en su búsqueda Lista de LINQ

var results = _List.Where(item => item == search).FirstOrDefault(); 

Esta búsqueda encontrará el primer o valor predeterminado que devolverá.

1

Si necesitamos encontrar un elemento de la lista, entonces podemos usar el método de extensiones Find y FindAll, pero hay una pequeña diferencia entre ellos. Aquí hay un ejemplo.

List<int> items = new List<int>() { 10, 9, 8, 4, 8, 7, 8 }; 

    // It will return only one 8 as Find returns only the first occurrence of matched elements. 
    var result = items.Find(ls => ls == 8);  
// this will returns three {8,8,8} as FindAll returns all the matched elements. 
     var result1 = items.FindAll(ls => ls == 8); 
0

Quiere buscar un objeto en la lista de objetos.

Esto lo ayudará a obtener el primer valor o valor predeterminado en su búsqueda en la Lista de Linq.

var item = list.FirstOrDefault(items => items.Reference == ent.BackToBackExternalReferenceId); 

o

var item = (from items in list 
    where items.Reference == ent.BackToBackExternalReferenceId 
    select items).FirstOrDefault(); 
Cuestiones relacionadas