2016-02-02 6 views
0

У меня есть два словаря информации, один из них поступает из базы данных, а другой - из локальных устройств.Как сравнить два словаря и создать новый в одном направлении

У меня есть метод, который сравнивает то, что находится на локальном устройстве, с тем, что находится в базе данных. Если на устройстве есть что-то, что нет в базе данных, я хочу добавить его в базу данных. Меня не волнует, есть ли что-то в базе данных, которая не на устройстве.

Вот метод, который я написал, чтобы справиться с этой задачей:

private static PackageHistory GetPkgChangeList(PackageHistory devicePackageHistory, PackageHistory databasePackageHistory) 
{ 
    var changeList = new PackageHistory(); 

    foreach (var devicePkg in devicePackageHistory.Keys) 
    { 
     // do we have a database entry for this package 
     var databaseEntryList = new List<Tuple<string, DateTime>>(); 
     if (databasePackageHistory.TryGetValue(devicePkg, out databaseEntryList)) 
     { 
      // compare entries, add missing to list 
      foreach (var deviceEntry in devicePackageHistory[devicePkg]) 
      { 
       // TODO: Not sure if the equality is done automatically 
       if (!databaseEntryList.Contains(deviceEntry)) 
       { 
        var changeListEntries = new List<Tuple<string, DateTime>>(); 
        if (changeList.TryGetValue(devicePkg, out changeListEntries)) 
        { 
         changeListEntries.Add(new Tuple<string, DateTime>(deviceEntry.Item1, deviceEntry.Item2)); 
        } 
        else 
        { 
         changeList.Add(devicePkg, new List<Tuple<string, DateTime>> { new Tuple<string, DateTime>(deviceEntry.Item1, deviceEntry.Item2)}); 
        } 
       } 
      } 
     } 
     else 
     { 
      // add missing package and its history to change list 
      changeList.Add(devicePkg, devicePackageHistory[devicePkg].ConvertAll(entry => new Tuple<string, DateTime>(entry.Item1, entry.Item2))); 
     } 
    } 

    return changeList; 
} 

Вот PackageHistory класс:

protected class PackageHistory : Dictionary<string, List<Tuple<string, DateTime>>> 
{ 
} 

Что происходит, я иду через все пункты в devicePackageHistory словаре и сравнивая их с элементами в databasePackageHistory.

Если я найду товар не в словаре databasePackageHistory, я добавлю его в словарь changeList. Этот changeList возвращается в конце функции и отправляется другому методу для дальнейшей обработки.

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

Я работаю с устаревшим кодом, поэтому у меня мало места для маневра. Как бы вы это сделали?

EDIT: В основном я обновляю свою базу данных и собирая эту информацию.

+0

Если в этом нет ошибок, [CodeReview] (http://codereview.stackexchange.com/), вероятно, будет лучшим местом для этого вопроса. – JRLambert

+0

Я так не думаю. Я думаю, что есть новая концепция, о которой я не знаю о сравнении словарей. Есть ли причудливые кодовые трюки, которые могут сделать это лучше? – visc

ответ

0

Предполагая, что вы можете использовать Linq:

(Это проверялось, извинения заранее, если это не работает точно так, как написано).

private static PackageHistory GetPkgChangeList(PackageHistory devicePackageHistory, PackageHistory databasePackageHistory) 
{ 
    return devicePackageHistory 
     .Except(databasePackageHistory, devicePackageHistory.Comparer) 
} 

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

Кроме того, слегка не связанный, Dictionary<string, List<Tuple<string, DateTime>>> выглядит так, что его можно было бы упростить до Dictionary<string, Dictionary<string, DateTime>>. Словарь - это в основном список кортежей.

1

Вы можете достичь этого с помощью linq.

Я собрал небольшой пример.

void Main() 
{ 
    Dictionary<string, int> primaryDict = new Dictionary<string, int> 
    { 
     {"key1", 33}, 
     {"key2", 24}, 
     {"key3", 21}, 
     {"key4", 17}, 
     {"key5", 12} 
    }; 

    Dictionary<string, int> secondaryDict = new Dictionary<string, int> 
    { 
     {"key1", 22}, 
     {"key3", 20}, 
     {"key4", 19}, 
     {"key7", 17}, 
     {"key8", 10} 
    }; 

    var resultDict = primaryDict.Where(x => !secondaryDict.ContainsKey(x.Key)) 
        .ToDictionary(x => x.Key, x => x.Value); 

    Console.WriteLine(resultDict); 
} 

Это возвращает все элементы в primaryDict, которые не являются в secondaryDict.

0

Если я правильно понял ваш код.Вы можете использовать что-то вроде этого:

var changeList = new PackageHistory(devicePackageHistory 
    .SelectMany(x => x.Value.Select(y => new Tuple<string, Tuple<string, DateTime>>(x.Key, y))) 
    .Except(databasePackageHistory.SelectMany(x => x.Value.Select(y => new Tuple<string, Tuple<string, DateTime>>(x.Key, y)))) 
    .GroupBy(x => x.Item1) 
    .ToDictionary(x => x.Key, x => x.Select(y => y.Item2).ToList())); 

Вам потребуется дополнительный конструктор, если в результате набора изменений должно быть типа PackageHistory:

public PackageHistory(IDictionary<string, List<Tuple<string, DateTime>>> source) : base(source) 
{ 
} 

Объяснение: Оба словари трансформируются в перечисления сравнимых элементов типа Tuple<string,Tuple<string,DateTime>> , Затем элементы, которые существуют (все элементы набора совпадают) в базе данных, исключаются из перечисления устройств. Затем возвращаемые элементы группируются в словарь по старому словарному ключу.

Edit: Альтернативный код без Linq:

var changeList = new PackageHistory(devicePackageHistory); 

foreach (var databasePkgKvp in databasePackageHistory) 
{ 
    var changeListEntries = new List<Tuple<string, DateTime>>(); 
    if (changeList.TryGetValue(databasePkgKvp.Key, out changeListEntries)) 
    { 
     foreach (var databaseEntry in databasePkgKvp.Value) 
     { 
      changeListEntries.Remove(databaseEntry); 
     } 
     if (changeListEntries.Count == 0) 
     { 
      changeList.Remove(databasePkgKvp.Key); 
     } 
    } 
} 
0

Если вам просто нужно обновить вещи обратно в базу данных, которые не находятся в, Оба словари могут быть объединены с помощью этого простого оператора. Здесь dictOne - словарные статьи из db, а dictTwo - словарные статьи с устройства.

var dict = dictOne.Concat(dictTwo).GroupBy(d => d.Key).ToDictionary(d => d.Key, d => d.First().Value); 

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