c # - сравнить два словаря, чтобы узнать каждую операцию добавления и каждую операцию удаления - PullRequest
1 голос
/ 14 сентября 2011

У меня есть 2 словаря с похожей структурой

Dictionary<string, List<int>> Origins

и

Dictionary<string, List<int>> Changes

Вначале я создал Origins.Это копия начального состояния.Пример:

Origins["toto"] = new List<int>(){1,2,3};
Origins["tata"] = new List<int>();
Origins["titi"] = new List<int>(){1,2};

После действия пользователя я сохраняю изменения в словаре изменений.Обычно пользователь может добавлять или удалять некоторые числа, связанные со строкой.Поэтому я сохраняю все следы любого изменения, например:

пример: если пользователь добавляет 1 в слове "tata" в словаре Изменения имеют "tata" имеют 1

если пользовательдобавить 4 в слове «toto» в словаре Изменения имеют «toto», имеют 1,2,3,4

, если пользователь удаляет 1 в словаре «titi». Изменения имеют иметь «titi» имеют 2

Мне нужен словарь Changes для того, чтобы знать, когда пользователь возвращается в исходное состояние, с простым сравнением.

Если для строки не выполняется никаких изменений, в словаре Changes нет записиэта строка.

После многих изменений пользователь может сохранить изменения.Поэтому теперь мне нужно найти все операции добавления и удаления.

Моя первая идея - сравнить два словаря, чтобы увидеть операцию добавления и операцию удаления.Но как ?Если я сравниваю списки для одной и той же строки, я могу знать разницу, но я застрял здесь.А может быть, есть лучший способ сделать это?Любое предложение?

Ответы [ 4 ]

2 голосов
/ 14 сентября 2011

У вас есть следующие случаи:

  1. Новый ключ строки добавляется к Changes вместе с некоторыми связанными значениями.
  2. Значения для существующего строкового ключа изменены (значения добавлены или удалены).

В случае (1) у вас будет запись в Changes, которая не существует в Origins. В случае (2) у вас будет запись в обоих, но с другим списком значений.

(Значения, которые я собираюсь предположить, являются математическим набором, то есть, что конкретное значение может появиться там только один раз и что порядок незначителен. Если это не так, вам придется несколько изменить подход.)

Чтобы определить случай (1), вы можете найти уникальные ключи:

IEnumerable<string> newKeys = Changes.Keys.Except(Origins.Keys);

Очевидно, что каждое значение в Changes для нового ключа необходимо будет «добавить». Вы можете просто перебрать перечисляемое newKeys и получить значения из Changes:

foreach (string key in newKeys)
{
    IEnumerable<int> addedValues = Changes[key];
    // your processing here
}

Чтобы обнаружить case (2), вам нужно будет выполнить итерацию словаря и сравнить набор значений в Changes с Origins. Для этого мы итерируем Origins, чтобы получить ключ и исходные значения, а затем извлекаем элемент, используя ключ из Changes. (Мы сделаем это примерно так, как если бы мы итерировали Changes, вместо этого мы потенциально могли бы получить новые, добавленные ключи, которых нет в Origins, и это другой случай, с которым нам пришлось бы иметь дело.)

foreach (KeyValuePair<string, List<int>> entry in Origins)
{
    List<int> originsValues = entry.Value;
    List<int> changesValues;

    // handle no key in Changes (as pointed out by Guillaume V). 
    if (!Changes.TryGet(entry.Key, out changesValues)) changesValues = originsValues;

    IEnumerable<int> removedValues = originsValues.Except(changesValues);
    IEnumerable<int> addedValues = changesValues.Except(originsValues);

    // your processing here
}
1 голос
/ 14 сентября 2011

Вы можете попробовать это:

        Dictionary<string, List<int>> Origin = new Dictionary<string, List<int>>();

        Origin["toto"] = new List<int>(){1,2,3};
        Origin["tata"] = new List<int>();
        Origin["titi"] = new List<int>(){1,2};


        Dictionary<string, List<int>> Changes = new Dictionary<string,List<int>>();

        Changes["toto"] = new List<int>() { 1, 2, 3, 4 };
        Changes["tata"] = new List<int>(){1};
        Changes["titi"] = new List<int>() { 2 };

        Dictionary<string, List<int>> ToRemove = new Dictionary<string, List<int>>();
        Dictionary<string, List<int>> ToAdd = new Dictionary<string, List<int>>();

        foreach (string key in Origin.Keys)
        {
            ToRemove[key] = Origin[key];
            ToAdd[key] = Changes[key];


            foreach (int i in ToRemove[key])
            {

                if (ToAdd[key].Contains(i)) //There is no change
                {
                    ToAdd[key].Remove(i);
                    ToRemove[key].Remove(i);
                }
            }
        }
0 голосов
/ 14 сентября 2011

вдохновленный Полом Руэйном и Матмотом, я развиваю свой собственный путь:

foreach (var change in this.Changes)
        {
            List<int> origin = this.Origins[change.Key];

            List<int> newValue = change.Value;

            //find the basic add and remove
            IEnumerable<int> remove = origin.Except(newValue);
            IEnumerable<int> add = newValue.Except(origin);

            if (!add.Any() && remove.Any())
            {
              //remove all in the remove list 
                continue;

            }
            else if (add.Any() && !remove.Any())
            {
              //add all in the add list
                continue;
            }

            //if in the same change there are add and remove 
            IEnumerable<int> dif1 = add.Except(remove);
            IEnumerable<int> dif2 = remove.Except(add);

            if (dif1.Any())
            {
                //add all in the dif1 list 

            }
            if (dif2.Any())
            {
                //remove all in  dif2 list


            }
        }

Что вы думаете об этом?

0 голосов
/ 14 сентября 2011

Если все, что вам нужно сделать, это определить, равны ли два объекта, я бы предложил создать свой собственный класс и переопределить Equals() и GetHashInfo():

public class ComparableDictionary : Dictionary<string, List<int>>
{
    private const int CouldBeAnyConstant = 392;

    public override bool Equals(object other)
    {
        return Equals((ComparableDictionary)other);
    }

    public bool Equals(ComparableDictionary other)
    {
        return other != null && (GetHashCode() == other.GetHashCode());
    }

    public override int GetHashCode()
    {
        int result = CouldBeAnyConstant;
        unchecked
        {
            foreach (var list in Values)
                foreach (var value in list)
                    result = result*value.GetHashCode();

            foreach (var value in Keys)
                result = result * value.GetHashCode();
        }

        return result;
    }

}

Тогда все, что вам нужно сделать, чтобы использовать его:

public bool UserHasMadeChanges(ComparableDictionary Origins, ComparableDictionary Changes)
{
    return !Origins.Equals(Changes)
}
...