2010-09-19 9 views
7

Tengo un conjunto de objetos modelo que tienen una propiedad pública IsVisible booleana. Todo lo que tengo que hacer es encontrar si al menos uno del conjunto tiene ese valor establecido en TRUE. En otras palabras, si tengo 10.000 objetos, pero el segundo es true, no necesito pasar por los otros 9.998. Ya tengo mi respuesta.Comprobación simple para ver si al menos un objeto en un conjunto tiene un valor de propiedad TRUE

Ahora sé que podría escribir mi propia función iterativa y partir al primer valor 'True', pero espero que eso sea algo que LINQ puede hacer. En realidad, ni siquiera necesita ser LINQ. Cualquier sugerencia es bienvenida.

Por cierto, el idioma de elección es C#.

Actualización:

Ver mi último post aquí. He agregado algunos códigos de prueba y tiempos. Parece que LINQ es bastante pobre en cuanto a rendimiento comparado con solo hacer la prueba yo mismo. Claro que es más fácil escribir, pero en tiempos críticos, ya no estoy seguro.

Lo que más me sorprendió es la mayoría de las veces que corrí esto, la enumeración fue ganada y un buen clip, pero por alguna razón, cuando envolví la prueba en múltiples pases, parece haber cambiado a indexación con un el conteo en caché es el más rápido.

También noté que si no reinicio todo a 'falso', todas las pruebas restantes/repetidas parecen MUCHO más rápidas. De alguna manera, volver a establecer todo en FALSE (que fue intencionalmente exagerado para probar exactamente esto ...) cambia las cosas.

Interesante. No estoy seguro de qué camino tomaré ahora. Este no es un sistema de misión crítica así que tal vez voy a ir por la legibilidad, pero aún así. Interesante.

+1

Al optimizar, debe sacrificar la velocidad de ejecución frente al costo del programador. La mayoría de los administradores de desarrollo prefieren comprar más servidores que pagar a más programadores, y solo una pequeña fracción de código se ejecuta en una ruta crítica. A menudo, el código que es más rápido de escribir y probar gana sobre el código que se ejecuta más rápido, cuando se tienen en cuenta todos los costos (incluido el costo del desarrollador). En mi experiencia, Linq es mucho más rápido de escribir, pero se ejecuta más lento. Todavía gana casi todo el tiempo en mi experiencia. – Slaggg

+0

Slagg, todavía no tiene suficientes puntos para votar comentarios, pero sé que si lo hiciera, obtendría uno para eso. Puede ser obvio, pero la brevedad de esto realmente se destaca (no muy diferente al punto que también lo hace! ¡Inteligente amigo! ¡Muy inteligente!) – MarqueIV

Respuesta

16

El método que está buscando es Enumerable.Any.

bool anyObjectsVisible = myObjects.Any(myObject => myObject.IsVisible); 

Tiene la semántica exacta de cortocircuito que está buscando; el código de ejemplo es similar a:

static bool AreAnyObjectsVisible(IEnumerable<MyObject> myObjects) 
{ 
    foreach (var myObject in myObjects) 
    { 
     if (myObject.IsVisible) return true; 
    } 

    return false; 
} 
+0

¡Eso es exactamente lo que estoy buscando! (Soy nuevo en LINQ. ¡No puedo creer que me haya perdido!) Intenté aceptar tu respuesta, pero me dice que tengo que esperar 12 minutos. Yo al menos lo voté. Por cierto, ¡Dios mío que fue rápido! ¡Ni siquiera fue un minuto desde que lo publiqué! ¡Rock! – MarqueIV

+0

@MarqueIV: Saludos. Aquí hay un gran recurso para aprender LINQ: http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx – Ani

+0

Hola Ari ... por tu comentario, desbordé mi prueba. PERO ... si desea incluir algo así de detallado, pero no es una respuesta (es decir, si desea formatear el código, etc.), ¿es la etiqueta adecuada para editar la pregunta original? (Sí, tienes razón, en este caso, debería haber sido una pregunta diferente, pero estoy hablando en términos más generales). – MarqueIV

3

Si necesita encontrar realmente un objeto, basta con utilizar el método .First o .FirstOrDefault:

var myObject = myCollection.First(x=>x.IsVisible); 

o

var myObject = myCollection.FirstOrDefault(x=>x.IsVisible); 

El único La diferencia entre ellos es que el método .First lanzará una excepción si no hay tal objeto en la colección cuando el segundo devuelve el valor predeterminado (nulo en este ejemplo).

Si sólo tiene que comprobar si hay algún objeto con este conjunto de propiedades, utilice

var thereIsVisibleObject = myCollection.Any(x=>x.IsVisible); 

Todos estos métodos dejan de iteración a través de la colección una vez que se encuentra el objeto correspondiente.

O, en caso de que compruebe si todos los objetos son visibles/invisibles, es posible hacer esto:

var allTheObjectsAreVisible = myCollection.All(x=>x.IsVisible); 
var allTheObjectsAreInvisible = myCollection.All(x=>!x.IsVisible); 

Pero el método .Todas se enumerar todos los elementos (que es obvio por su nombre)

+0

Te voté, pero Ani recibió la 'Respuesta aceptada' porque respondieron dentro de los 60 segundos de mi publicación. (¡Incluso antes de que tuviera la oportunidad de editar un error tipográfico!) Pero esta también es una gran información, así que te voté. ¡¡Gracias!! – MarqueIV

+0

En realidad, acabo de volver a leer sus comentarios sobre 'Todos'. Corrígeme si me equivoco, pero NO enumerará todos los objetos si tu predicado devuelve falso, ya que debería devolver falso de manera inmediata, por lo que tu comentario es que enumerarán todo lo que no sé si es correcto. Después de todo decir '¿hay algún visible' debería cortocircuitar lo mismo que decir '¿están todos visibles' si incluso uno es visible, correcto? (La única diferencia es que uno devuelve cierto, el otro falso.) Por supuesto que estoy basando eso en la lógica y no en la documentación, así que no puedo decirlo con certeza. – MarqueIV

+0

Estoy en lo correcto. .All() itera a través de la colección que le proporciona y lo devuelve tan pronto como su predicado es falsa. –

0

Aquí es un ".Cualquier()" aplicación:

public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 
{ 
    if (source == null) 
    { 
     throw Error.ArgumentNull("source"); 
    } 
    if (predicate == null) 
    { 
     throw Error.ArgumentNull("predicate"); 
    } 
    foreach (TSource local in source) 
    { 
     if (predicate(local)) 
     { 
      return true; 
     } 
    } 
    return false; 
} 

Así que aquí está ella, nada "especial" con .Any(), que es sólo una envoltura alrededor de "foreach". Nada especial para probar allí y nada que culpar en términos de optimización micro-micro-micro.

+0

Sus optimizaciones de micro-micro-micro comentan aparte, aún es interesante que mi código, que se ve casi idéntico al que publicó (sin las comprobaciones nulas) funcionó hasta 400% más rápido que LINQ en algunos casos. A eso me estaba refiriendo. – MarqueIV

Cuestiones relacionadas