我正在尝试比较加载的两个词典。每个人都包含一个ID和一个Individual对象。
到目前为止的代码是
_Individuals1 = file1.fileIndividuals;
_Individuals2 = file2.fileIndividuals;
foreach (KeyValuePair<int, Individual> kvpInd in _Individuals1)
{
foreach (KeyValuePair<int, Individual> kvpInd2 in _Individuals2)
{
if (kvpInd.Value.name.name == kvpInd2.Value.name.name)
{
similarInds.Add(kvpInd.Key, kvpInd.Value);
}
}
}
我得到的错误是“已经添加了具有相同键的项目”。 我可以看到为什么,但我不知道如何以不同的方式去做它的工作。有人可以帮忙吗?
谢谢
答案 0 :(得分:1)
这里的问题是你对不同Dictionary<TKey, TValue>
个实例中的键和值之间的关系有一个错误的假设。多个条目很可能具有不同的键但具有相同的值。如果在_Individuals2
中发生这种情况,那么您最终会将相同的密钥添加到字典中两次。考虑
地图1
地图2
在这种情况下,Map2中的多个值具有值Dog。所以我最终基本上根据你的算法
执行以下操作// 1:Dog matches 2:Dog
similarInds.Add(1, "Dog");
// 1:Dog matches 3:Dog
similarInds.Add(1, "Dog");
看起来你想要的只是简单地知道两个地图之间相似的Individual
个对象集。如果是,则只需存储该值并使用Set<Individual>
以防止重复。
var similarInds = new HashSet<Individual>();
...
similarInds.Add(kvpInd.Value);
答案 1 :(得分:1)
您可以在字典中使用相同值的多个条目。您无需检查或比较密钥。
因此,_Individuals2中有多个条目具有相同的值,但它们具有不同的键。
我不知道你在这里做了什么,但我认为你的关键应该是每个对象的独特之处,他们真的不应该比较这些值。如果您使用列表或类似的东西,您可以使用交叉点方法返回它们的共同点。
或者你可以使用
_Individuals1.Values.Intersect(_Individuals2.Values);
此外,在使用泛型时,几乎总是能够覆盖存储在泛型中的对象的相等运算符。那你就不必做以下事情:
if (kvpInd.Value.name.name == kvpInd2.Value.name.name)
答案 2 :(得分:1)
以下是使用lambdas的方法:
var similarInds = file1.fileIndividuals.
Where(kv1 => file2.fileIndividuals.Any(kv2 => kv1.Value.name.name == kv2.Value.name.name)).
ToDictionary(kv => kv.Key, kv => kv.Value);
答案 3 :(得分:0)
我们在这里退后一步。你有两个词典,将个人键入一个整数。但是,您不是要比较相对词典的键,而是比较它们的值。这让我觉得钥匙不是唯一的。
听起来你想要的是两个词典的完全外连接:
这可以通过一些Linq来完成。理解这不是最可能的解决方案,但是更容易理解正在发生的事情。
//get records from 1 that aren't in 2
var left = _Individuals1.Where(l=>!_Individuals2.Any(r=>l.Value.Name == r.Value.Name));
//get records that appear in both 1 and 2,
//using the select clause to "merge" the data you want from each side
var join = from l in _Individuals1
join r in _Individuals2 on l.Value.Name equals r.Value.Name
select new KeyValuePair<int, Individual>(l.Key, r.Value);
//get records from 2 that aren't in 1
var right = _Individuals2.Where(r=>!_Individuals1.Any(l=>l.Value.Name == r.Value.Name));
//Now, the keys from the left and join enumerables should be consistent,
//because we used the keys from _Individuals1 in both of them.
var merged = left.Concat(join).ToDictionary(x=>x.Key, x=>x.Value);
//BUT, keys from records that only existed in 2 may have duplicate keys,
//so don't trust them
var maxKey = merged.Keys.Max();
foreach(var r in right)
merged.Add(++maxKey, r.Value);
通过构造生成“join”的查询来生成左连接而不是我显示的内连接,可以避免显式创建“left”可枚举。您还可以尝试使用_Individuals2中的键,通过针对合并的目录检查每个键。该代码看起来像这样:
var maxKey = merged.Keys.Max();
foreach(var r in right)
if(merged.ContainsKey(r.Key))
merged.Add(++maxKey, r.Value);
else
{
merged.Add(r.Key, r.Value);
maxKey = r.Key > maxKey ? r.Key : maxKey;
}
只要密钥不重复,这将安全地使用来自_Individuals2的密钥,因此应该使用来自_Individuals2的一些(但可能不是全部)密钥。这是否“更好”取决于具体情况。