如何比较两个词典并在一个方向上创建一个新词典

时间:2016-02-02 21:35:46

标签: c# dictionary

我有两个信息字典,一个来自数据库,另一个来自本地设备。

我有一种方法可以比较本地设备上的内容与数据库中的内容。如果设备上的某些内容不在数据库中,我想将其添加到数据库中。我不在乎数据库中是否存在设备上没有的东西。

这是我写的一个处理这项工作的方法:

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在函数末尾返回,并发送到另一个方法进行进一步处理。

我知道GetPkgChangeList算法看起来很复杂,这就是为什么我会询问是否有更简单的方法来比较两个字典与我拥有的类型,并创建一个包含这些更改的新字典(中的项目)设备字典而不是数据库字典。)

我正在使用遗留代码,因此我没有太多的摆动空间。你会怎么做?

编辑:基本上我正在更新我的数据库并收集这些信息。

4 个答案:

答案 0 :(得分: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中的所有元素。

答案 1 :(得分:0)

假设您可以使用Linq:

(这是未经测试的,如果这不能完全按照书面说明的那样提前道歉)。

Dictionary<string, List<Tuple<string, DateTime>>>

另一个假设是设备上和数据库中项目之间相等的决定因素是字典密钥。

此外,稍微不相关,Dictionary<string, Dictionary<string, DateTime>>似乎可以简化为public static final MyPayLoad parseBinaryPayload(byte[] payload) { DatumReader<MyPayLoad> payloadReader = new SpecificDatumReader<>(SCHEMA_V1, SCHEMA_V2); Decoder decoder = DecoderFactory.get().binaryDecoder(payload, null); MyPayLoad myPayLoad = null; try { myPayLoad = payloadReader.read(null, decoder); } catch (IOException e) { logger.log(Level.SEVERE, e.getMessage(), e); } return myPayLoad; } 。字典基本上是元组列表。

答案 2 :(得分: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>>的可比项的枚举。然后,数据库中存在的项(所有元组项匹配)将从设备枚举中排除。然后,生成的项目将按旧字典键分组回字典。

编辑:没有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);
        }
    }
}

答案 3 :(得分:0)

如果您只需要将数据更新回不存在的数据库,则可以使用此简单语句合并这两个词典。这里dictOne是来自db的字典项目,dictTwo是来自设备的字典项目。

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

考虑到元组和其他内容,这段代码需要根据您的要求进行一些更改。