web-dev-qa-db-fra.com

Filtrage des valeurs d'un dictionnaire générique C #

J'ai un dictionnaire C #, Dictionary<Guid, MyObject> que je dois filtrer en fonction d'une propriété de MyObject.

Par exemple, je veux supprimer tous les enregistrements du dictionnaire où MyObject.BooleanProperty = false. Quel est le meilleur moyen d'y parvenir?

Puisque Dictionary implémente IEnumerable<KeyValuePair<Key, Value>>, vous pouvez simplement utiliser Where :

var matches = dictionary.Where(kvp => !kvp.Value.BooleanProperty);

Pour recréer un nouveau dictionnaire si vous en avez besoin, utilisez la méthode ToDictionary .

52
Lee

Si vous ne vous souciez pas de créer un nouveau dictionnaire avec les éléments désirés et de jeter l'ancien, essayez simplement:

dic = dic.Where(i => i.Value.BooleanProperty)
         .ToDictionary(i => i.Key, i => i.Value);

Si vous ne pouvez pas créer un nouveau dictionnaire et que vous devez modifier l'ancien pour une raison quelconque (comme lorsqu'il est référencé en externe et que vous ne pouvez pas mettre à jour toutes les références:

foreach (var item in dic.Where(item => !item.Value.BooleanProperty).ToList())
    dic.Remove(item.Key);

Notez que ToList est nécessaire ici, car vous modifiez la collection sous-jacente. Si vous modifiez la collection sous-jacente, l'énumérateur qui y travaille pour interroger les valeurs sera inutilisable et lève une exception lors de la prochaine itération de la boucle. ToList met en cache les valeurs avant de modifier le dictionnaire.

81
Mehrdad Afshari

Vous pouvez simplement utiliser la clause Linq where:

var filtered = from kvp in myDictionary
               where !kvp.Value.BooleanProperty
               select kvp
7
Oded
    public static Dictionary<TKey, TValue> Where<TKey, TValue>(this Dictionary<TKey, TValue> instance, Func<KeyValuePair<TKey, TValue>, bool> predicate)
    {
        return Enumerable.Where(instance, predicate)
                         .ToDictionary(item => item.Key, item => item.Value);
    }
1
Ryan Williams

J'ai ajouté la méthode d'extension suivante pour mon projet qui vous permet de filtrer un IDictionary.

public static IDictionary<keyType, valType> KeepWhen<keyType, valType>(
    this IDictionary<keyType, valType> dict,
    Predicate<valType> predicate
) {
    return dict.Aggregate(
        new Dictionary<keyType, valType>(),
        (result, keyValPair) =>
        {
            var key = keyValPair.Key;
            var val = keyValPair.Value;

            if (predicate(val))
                result.Add(key, val);

            return result;
        }
    );
}

Usage:

IDictionary<int, Person> oldPeople = personIdToPerson.KeepWhen(p => p.age > 29);
0
aaaaaa

Voici une solution générale, travaillant non seulement pour les propriétés booléennes des valeurs.

Méthode

Rappel: les méthodes d'extension doivent être placées dans des classes statiques. N'oubliez pas l'instruction using System.Linq; en haut du fichier source.

    /// <summary>
    /// Creates a filtered copy of this dictionary, using the given predicate.
    /// </summary>
    public static Dictionary<K, V> Filter<K, V>(this Dictionary<K, V> dict,
            Predicate<KeyValuePair<K, V>> pred) {
        return dict.Where(it => pred(it)).ToDictionary(it => it.Key, it => it.Value);
    }

tilisation

Exemple:

    var onlyWithPositiveValues = allNumbers.Filter(it => it.Value > 0);
0
Andi