2011-04-10 8 views
24

No estoy en soluciones de LINQ,¿Cómo puedo eliminar artículos de diccionario utilizando la expresión lambda

estoy usando prédicat simple para determinar si la clave debe ser eliminado, Por ejemplo, si el diccionario es construir como Dictionary<int, int>, Entonces, ¿cómo debería eliminar todas las entradas con los datos negativos

estoy prefiere utilizar el mismo diccionario, no crear uno nuevo, no tengo emite preformance

¿hay una manera de hacerlo, sin usar LINQ, pero usando Expresiones Lambda?

No quería soluciones en LINQ porque nadie las está utilizando en mi proyecto, no quería ser la primera ..., pero como vi que las soluciones LINQ se veían mejor, las usaré ...

+0

datos negativos en clave o valor? ¿o ambos? – MonkeyDeveloper

+0

Creo que no puede usar expresiones lambda sin linq en este caso –

Respuesta

50

la forma más sencilla es probablemente para crear un nuevo diccionario , si eso está bien para usted:

var newDictionary = oldDictionary.Where(pair => pair.Value >= 0) 
           .ToDictionary(pair => pair.Key, 
               pair => pair.Value); 

Si tiene para mutar el diccionario existente (por ejemplo, debido a que varios otros objetos tienen referencia a la mismo diccionario) necesitarías construir una lista de claves para eliminar, luego eliminarlos después:

var toRemove = dictionary.Where(pair => pair.Value < 0) 
         .Select(pair => pair.Key) 
         .ToList(); 

foreach (var key in toRemove) 
{ 
    dictionary.Remove(key); 
} 

EDIT: Acabo de notar la primera frase: "No estoy en soluciones LINQ". Si eso significa que no quiere uso una solución LINQ, aquí está la versión de mano:

List<int> toRemove = new List<int>(); 
foreach (KeyValuePair<int, int> pair in dictionary) 
{ 
    if (pair.Value < 0) 
    { 
     toRemove.Add(pair.Key); 
    } 
} 

foreach (var key in toRemove) 
{ 
    dictionary.Remove(key); 
} 

... pero si puede utilizar LINQ, me animo haces. Mi segunda solución es equivalente a la versión "a mano", pero OMI más legible.

+0

¿Qué referencia debo agregar para admitir la palabra clave 'Dónde'? – Delashmate

+1

@Delashmate: agregue una referencia a 'System.Core' y agregue' using System.Linq; '. Esto supone que estás usando .NET 3.5 o superior. –

+0

@Delashmate: Acabo de ver lo poco que dice que "no estás en las soluciones LINQ": ¿te refieres a que no tienes experiencia en ellas, o no quieres * una solución LINQ? –

2
var toRemove = dict.Keys.Where(predicate).ToArray(); 
foreach (var key in toRemove) { 
    dict.Remove(key); 
} 
+1

Tenga en cuenta que ToList es generalmente más eficiente que ToArray. A menos que * necesite * una matriz, ToList es la IMO preferida. –

+0

@Jon, no es que lo dude, pero ¿por qué sería eso? ¿No es una matriz una estructura más ligera que una lista? – mikel

+6

@mikel: una matriz tiene que ser * exactamente * el tamaño correcto. La forma en que normalmente construyes una colección "grande" es duplicando el tamaño de un buffer cada vez que lo necesites. Eso funciona bien para una lista en la que simplemente puede usar el búfer de gran tamaño después, pero si necesita una matriz después, a menudo tendrá que copiar todos los datos en el búfer en una * nueva * matriz de exactamente el tamaño correcto. Consulte http://msmvps.com/blogs/jon_skeet/archive/2011/01/02/reimplementing-linq-to-objects-part-24-toarray.aspx para obtener más información acerca de lo que ToArray debe hacer. –

0

¿Desea eliminar los elementos de ese diccionario, o está contento de utilizar un nuevo diccionario sin esos elementos incluidos?

var d = new Dictionary<int,int>(); 
var newDict = d.Where(entry => entry.Value >= 0).ToDictionary(entry => entry.Key, entry => entry.Value); 
0

más fácil uno:

Dictionary<long, long> dict... 
Dictionary<long, long> result = dict.Were(x => x.Value >= 0).ToDictionary(x => x.Key, x => x.Value); 

O simplemente un bucle sobre todo en 'para' en orden inverso y eliminar las no válidas.

6

Por la mera utilización de la expresión lambda:

foreach (var i in myDict.Where(d => (d.Value < 0 || d.key <0)).ToList()) 
{ 
    myDict.Remove(i.Key); 
} 
1

Bueno, si usted añadir

namespace MMExtensions 
{ 
    public static class DictionaryExtensions 
    { 
     public delegate bool Predicate<TKey, TValue>(KeyValuePair<TKey, TValue> d); 

     [MethodImpl(MethodImplOptions.Synchronized)] 
     public static void Filter<TKey, TValue>(
      this Dictionary<TKey, TValue> hashtable, Predicate<TKey, TValue> p) 
     { 
      foreach (KeyValuePair<TKey, TValue> value in hashtable.ToList().Where(value => !p(value))) 
       hashtable.Remove(value.Key); 
     } 
    } 
} 

y que tenía algunos datos como el diccionario:

Dictionary<string, int> d = 
      new Dictionary<string, int> {{"v", -3}, {"val1", 1}, {"val2", 2}}; 

entonces se podría usar:

d.Filter(delegate(KeyValuePair<string, int> kv) { return kv.Value >= 0; }); 
    d.Filter(kv => kv.Value >= 0);// or as lambda 
+0

No creo que necesites 'MethodImplOptions.Synchronized' aquí – RobSiklos

Cuestiones relacionadas