Utilisation de IEnumerable.Except sur KeyCollection vs exploitation de Dictionary.ContainsKey pour les soustractions et les intersections mutuelles en

I have two dictionaries Dictionary. I need to find their intersection (I mean only their keys intersection) and A\B and B\A subtractions and make some actions to the objects (in fact my objects are EntityFramework entities and I have to mark their state as Modified, Added and Deleted respectively, though it's not very relevant to the question). Just imagine the simplest Venn diagram.

Je veux le faire de la manière la plus efficace. Je pense avoir deux choix:

1) Implémenter un ensemble de méthodes d'extension génériques qui exploitent en interne les méthodes IEnumerable sur KeyCollection comme ExceptByKey , par exemple:

public static Dictionary ExceptByKeys(this Dictionary dict1, Dictionary dict2)
{
    return dict1.Keys.Except(dict2.Keys).ToDictionary(key => key, key => dict1[key]);
}

Then I could operate these methods to separately process each of three groups. From there I know that KeyCollection.Contains method internally uses the Dictionary.ContainsKey method so both are O(1). So my Except method would then run in O(n), is that right? I would need to use it once for each dictionary and also somehow detect the intersected part, which can be done implicitly though by first iterating over all entities in one dictionary and marking them as belonging to the intersection. So, is it like O(n) + O(n + m)?

2) Je pourrais aussi itérer sur mes dictionnaires en appelant la méthode ContainsKey sur l'autre dictionnaire pour chaque élément et faire la chose appropriée. Cela me semble une meilleure solution car je n'ai que la complexité O (n + m).

Donc, les questions sont: - Ai-je raison dans mes calculs? - Y at-il un meilleur moyen que je n'ai pas pensé à accomplir ce que je veux?

MISE À JOUR 19/06/2015

J'ai donc choisi le second cas et cela fonctionne bien. Voici ma mise en œuvre dans la nature

using (var he = new HostEntities())
{
    var dbHardDrives = he.HardDrive.Where(_ => _.HostName == _address).ToDictionary(_ => _.Name, _ => _);
    foreach (var dbHd in dbHardDrives)
    {
        if (wmiHardDrives.ContainsKey(dbHd.Key))
        {
            he.Entry(dbHd.Value).State = EntityState.Detached;
            he.Entry(wmiHardDrives[dbHd.Key]).State = EntityState.Modified;
        }
        else
        {
            he.Entry(dbHd.Value).State = EntityState.Deleted;
        }
    }
    foreach (var wmiHd in wmiHardDrives)
    {
        if (!dbHardDrives.ContainsKey(wmiHd.Key))
        {
            he.Entry(wmiHd.Value).State = EntityState.Added;
        }
    }
    he.SaveChanges();
}
0

1 Réponses

Ton raisonnement me semble bien. LINQs Except() parcourt la première collection en la plaçant dans un HashSet avant de parcourir la seconde collection, en effectuant des recherches sur le HashSet . O (n + m). Votre méthode d'extension est donc O (n + m) aussi. Comme vous le mentionnez, si vous voulez calculer les 3 ensembles d'ajouts, de suppressions et d'intersections, vous devrez l'appeler plusieurs fois, ce qui rend l'option 2 plus préférable.

Vous essayez de faire une jointure externe, et être en mesure d'évaluer les éléments de gauche, intérieur et droit séparément. Pour une solution O (n + m), vous pouvez utiliser quelque chose comme ça

public static JoinResult JoinKeys(this IDictionary first, IDictionary second)
{
    var left = new List();
    var inner = new HashSet();   //HashSet to optimize lookups
    var right = new List();

    foreach (var l in first.Keys)  //O(n)
    {
        if (second.ContainsKey(l))
            inner.Add(l);
        else
            left.Add(l);
    }

    foreach (var r in second.Keys)     //O(m) (longhand for clarity)
    {
        if (!inner.Contains(r))
            right.Add(r);
    }

    return new JoinResult
    {
        Left = left,
        Inner = inner,
        Right = right
    };
}

public class JoinResult
{
    public IEnumerable Left { get; set; }
    public IEnumerable Inner { get; set; }
    public IEnumerable Right { get; set; }
}
0
ajouté
Merci d'avoir répondu! J'ai fini par mettre en place la même chose, voir mes mises à jour.
ajouté l'auteur Varvara Kalinina, source