2011-06-29 16 views
8

estoy mirando algo de código que toma un IEnumerable<T> y la convierte en una List<T> por lo que puede utilizar List<T>.Find(predicate):LINQ equivalente a la lista <T> .Find()?

var myEnumerable = ...; 
var myList = new List<T>(myEnumerable); 
var match = myList.Find(value => value.Aaa == aaa && value.Bbb == bbb); 

¿Hay una manera de volver a escribir esto usando el LINQ extension methods que tiene el mismo efecto, pero sin construyendo un List<T> extra como un paso intermedio?

El método de extensión FirstOrDefault(source, predicate) parece un buen candidato, pero tratando de averiguar si es exactamente equivalente a Find está haciendo que me duela la cabeza.

Respuesta

10

El equivelent LINQ sería utilizar FirstOrDefault:

var match = myEnumerable.FirstOrDefault(value => value.Aaa == aaa && value.Bbb == bbb); 
+0

Eso es lo que sospechaba, pero es bueno escuchar la confirmación de alguien con más representante que yo (sonrisa). Entonces, ¿esto se ocupa de todos los casos extremos de la misma manera? (Colección vacía, nada que coincida, cualquier otra condición excepcional) –

+0

@Joe: Sí. Le dará los mismos resultados: la primera coincidencia, o 'predeterminada (T)' en el caso de que no haya elementos coincidentes. Es efectivamente idéntico, excepto que funciona en cualquier 'IEnumerable ' –

1

o se puede hacer de la siguiente manera:

var match = myEnumerable.Where(value => value.Aaa == aaa && value.Bbb == bbb) 
         .FirstOrDefault(); 
+0

Esto es consultar dos veces, que no es necesario porque puede lograr el resultado deseado solo con FirstOrDefault –

+2

@danderson: No es cierto - LINQ utiliza la ejecución diferida, por lo que la "consulta "dejará de ejecutarse tan pronto como se encuentre el primer elemento. Esto realmente no es mucho menos eficiente que usar FirstOrDefault directamente [muy ligeramente menos eficiente, pero solo microscópicamente]. Todavía hay como máximo una iteración a través de la secuencia ... –

+0

Realicé algunas pruebas de rendimiento y verifiqué esto, pero ¿conoce también algún artículo, documento técnico o enlace de MSDN que explique cómo funciona LINQ bajo el capó? Todavía no encontré ninguno en MSDN –

13

Sólo como referencia, se acompaña un cuadro de un viejo estilo de .NET 2 List<> métodos de instancia y sus métodos de extensión equivalentes en Linq:

METHOD IN List<>        METHOD IN Linq 
------------------------------------------------------------------------------------------ 

list.Contains(item)       query.Contains(item) 

list.Exists(x => x.IsInteresting())   query.Any(x => x.IsInteresting()) 
list.TrueForAll(x => x.IsInteresting())  query.All(x => x.IsInteresting()) 

list.Find(x => x.IsInteresting())    query.FirstOrDefault(x => x.IsInteresting()) 
list.FindLast(x => x.IsInteresting())   query.LastOrDefault(x => x.IsInteresting()) 

list.FindAll(x => x.IsInteresting())   query.Where(x => x.IsInteresting()) 

list.ConvertAll(x => x.ProjectToSomething()) query.Select(x => x.ProjectToSomething()) 

Por supuesto, algunos de ellos no son totalmente equivalentes. En particular, Where y Select de Linq usan la ejecución diferida, mientras que FindAll y ConvertAll de List<> se ejecutarán inmediatamente y devolverán una referencia a una nueva instancia de List<>.

FindLast a menudo será más rápido que LastOrDefault porque FindLast en realidad busca desde el final de List<>. Por otro lado, LastOrDefault(predicate) siempre se ejecuta a través de la secuencia completa (comenzando desde el primer elemento) y solo luego devuelve la coincidencia más "reciente".

+2

Gran respuesta y comentario interesante sobre FindLast en comparación con LastOrDefault. –

Cuestiones relacionadas