2009-05-22 13 views
5

Actualmente estoy usando el siguiente código para lograr esto, pero parece que debería haber algo mejor ... ¿sugerencias? Simplemente me parece que debería haber una manera de saltarse el foreach ...Al usar una cláusula LINQ Where en un diccionario, ¿cómo puedo devolver un diccionario del mismo tipo?

Dictionary<string,string> getValidIds(Dictionary<string,string> SalesPersons,List<string> ids) 
{ 
    Dictionary<string,string> o = new Dictionary<string,string>(); 
    var ie = SalesPersons.Where<KeyValuePair<string, string>>(t => ids.Contains(t.Key)); 
    foreach (var i in ie) 
    { 
     o.Add(i.Key, i.Value); 
    } 
    return o; 
} 

Respuesta

5

parece ser un montón de quejarse de buscar las cosas en la lista. Si la lista solo contiene algunos elementos, entonces no es gran cosa. Si la Lista contiene miles de elementos, querrá buscar O (1) en ella. HashSet puede proporcionar esto.

Dictionary<string, string> getValidIds(
    Dictionary<string, string> SalesPersons, 
    List<string> ids 
) 
{ 
    HashSet<string> idsFast = new HashSet<string>(ids); 
    Dictionary<string, string> result = SalesPersons 
    .Where(kvp => idsFast.Contains(kvp.Key)) 
    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value) 
    return result; 
} 
9

Bastante seguro de que sólo podría llamar ToDictionary en el resultado de la llamada Dónde:

Dictionary<string, string> GetValidIds(Dictionary<string, string> salesPersons, 
    IList<string> ids) 
{ 
    return salesPersons 
     .Where(p => ids.Contains(p.Key)) 
     .ToDictionary(p => p.Key, p => p.Value); 
} 
+0

Véase mi respuesta para las notas de rendimiento ... –

+0

1, Marc, aunque creo que si usted está preocupado acerca de Potencia con este tipo de cosas que tienes demasiado en la memoria, ya que es! :) –

+1

@Matt ... bueno, tal vez - pero hay un punto donde O (1)/O (N * log (N)) * no es * irrazonable, pero O (N^2) * es * a problema - si eso es 1k, 10k o 100k depende del proceso específico, por supuesto. –

6

Curiosamente, si enumerar sobre el diccionario (longitud N) primero y verificar la lista (longitud M) para su inclusión, luego obtiene el rendimiento de O (NM).

Puede construir un HashSet<> de los identificadores, pero parece redundante ya que ya tenemos un diccionario (previamente codificado) disponible.

Me gustaría iterar primero sobre los identificadores; dado que la búsqueda del diccionario (por clave) es O (1), esto le da un rendimiento de O (M); sin embargo, esto podría significar que no usa LINQ (ya que TryGetValue no le encantará LINQ (y presentar una tupla es demasiado como el trabajo duro) ...

Dictionary<string, string> getValidIds(
      IDictionary<string, string> salesPersons, 
      IEnumerable<string> ids) { 
     var result = new Dictionary<string, string>(); 
     string value; 
     foreach (string key in ids) { 
      if (salesPersons.TryGetValue(key, out value)) { 
       result.Add(key, value); 
      } 
     } 
     return result; 
    } 

no me preocupa demasiado que esto es más líneas que la versión de LINQ, elimina un O (N) de la complejidad ...


Editar; el siguiente podría funcionar (no lo he probado), pero creo que es un abuso de LINQ, y ciertamente no se escalará a PLINQ, etc. ... ¡lo uso con extrema precaución! También creo el enfoque foreach simplemente tiene menos gastos, por lo que será más rápido ... de todos modos:

Dictionary<string, string> getValidIds(
     IDictionary<string, string> salesPersons, 
     IEnumerable<string> ids) 
    { 
     string value = null; 
     return (from key in ids 
       where salesPersons.TryGetValue(key, out value) // HACK: v. dodgy 
       select new { key, value }) 
       .ToDictionary(x=>x.key, x=>x.value); 
    } 
Cuestiones relacionadas