2009-04-27 6 views
65

tengo un diccionario de tipoComprobar si KeyValuePair existe con FirstOrDefault de LINQ

Dictionary<Guid,int> 

quiero devolver el primer caso en el que se cumple una condición usando

var available = m_AvailableDict.FirstOrDefault(p => p.Value == 0) 

Sin embargo, ¿cómo puedo comprobar si ¿De verdad estoy obteniendo un KeyValuePair? Parece que no puedo usar! = Or == para verificar contra el valor predeterminado (KeyValuePair) sin un error de compilación. Hay un hilo similar here que parece no tener solución. De hecho, puedo resolver mi problema particular obteniendo la clave y comprobando el valor predeterminado de Guid, pero tengo curiosidad de saber si hay una buena forma de hacerlo con el par de valores clave. Gracias

+0

encontré [esta respuesta a otra pregunta] (http://stackoverflow.com/a/7153921/945456) fue útil. Básicamente use '.Where()' y luego use '.Any()' en el resultado de eso para decidir si obtuvo un resultado o no. –

Respuesta

89

Si te preocupas por la existencia, puedes usar ContainsValue(0) o Any(p => p.Value == 0) en su lugar? La búsqueda por valor es inusual para un Dictionary<,>; si buscaba por clave, podría usar TryGetValue.

Otro enfoque:

var record = data.Where(p => p.Value == 1) 
    .Select(p => new { Key = p.Key, Value = p.Value }) 
    .FirstOrDefault(); 

Esto devuelve una clase- por lo que será null si no lo encuentra.

+5

Ese es un buen truco usando tipos anónimos para enmascararse como estructuras. Tendré que recordar eso. –

+3

@Andre se están haciendo pasar por tuplas más que nada ... –

+1

No, eso no es lo que quise decir. Las tuplas son más simples, por lo que no tiene sentido pensar que los tipos anónimos están "tratando de parecerse a las tuplas". La idea detrás de mi comentario fue que si usas 'var', puedes reemplazar una estructura con un tipo anónimo sin ninguna corrección de referencia, como hiciste anteriormente. –

2

se puede comprobar si

available.Key==Guid.Empty 
+2

A menos que Guid. Empty es una clave potencialmente válida ... –

+0

sí, por supuesto. – pomarc

22

sugiero que lo cambie de esta manera:

var query = m_AvailableDict.Where(p => p.Value == 0).Take(1).ToList(); 

Se puede ver entonces si la lista está vacía o no, y toma el primer valor si se trata de no, por ejemplo

if (query.Count == 0) 
{ 
    // Take action accordingly 
} 
else 
{ 
    Guid key = query[0].Key; 
    // Use the key 
} 

Tenga en cuenta que no hay un concepto real de una entrada de "primera" en un diccionario - el orden en el que se reiteró que no está bien definido. Si desea obtener el par clave/valor que fue primer ingresado con ese valor, necesitará algún tipo de diccionario de conservación de pedidos.

(Esto es suponiendo que realmente desea saber la clave - si estás justo después de una comprobación de la existencia, Marc's solution es el más apropiado.)

+0

@Jon - para evitar la necesidad de una lista, etc., ver mi actualización. –

9

Lo que queremos es un método Any que proporciona la elemento coincidente también. Puede escribir fácilmente este método usted mismo.

public static class IEnumerableExtensions 
{ 
    public static bool TryGetFirst<TSource>(this IEnumerable<TSource> source, 
              Func<TSource, bool> predicate, 
              out TSource first) 
    { 
    foreach (TSource item in source) 
    { 
     if (predicate(item)) 
     { 
     first = item; 
     return true; 
     } 
    } 

    first = default(TSource); 
    return false; 
    } 
} 
+0

Creo que probablemente llamaría a esto TryGetFirst o TryFirst, dada su similitud con TryGetValue/TryParse. –

+0

TryGetFirst es bastante bueno. Pero al final puedes nombrarlo como quieras. – Samuel

+0

(Pero buena idea para un método de extensión - +1 :) –

11

Utilice la palabra clave predeterminada().

bool exists = !available.Equals(default(KeyValuePair<Guid, int>)); 
+1

Creo que el resultado debe invertirse, ya que: bool existe =! Disponible.Equals (predeterminado (KeyValuePair )); – Jaime

+0

Sí, tienes razón. ¡Gracias! –

0

una manera de comprobar respecto al valor predeterminado de una estructura tal como KeyValuePair sin especificar el tipo es crear una nueva instancia utilizando Activador:

if (available.Equals(Activator.CreateInstance(available.GetType()))) 
{ 
    Console.WriteLine("Not Found!"); 
} 
+0

Creo que esto es probablemente similar a la respuesta de Florian usando la palabra clave default(). Su enfoque puede ser más lento en tiempo de ejecución. –

Cuestiones relacionadas