比较两个字典并将字典值添加到另一个字典C#
我正在试着比较两本加载的词典。每个个体都包含一个ID和一个对象 到目前为止,代码是比较两个字典并将字典值添加到另一个字典C#,c#,dictionary,comparison,C#,Dictionary,Comparison,我正在试着比较两本加载的词典。每个个体都包含一个ID和一个对象 到目前为止,代码是 _Individuals1 = file1.fileIndividuals; _Individuals2 = file2.fileIndividuals; foreach (KeyValuePair<int, Individual> kvpInd in _Individuals1) { foreach (
_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);
}
}
}
\u Individuals1=file1.fileIndividuals;
_Individuals2=file2.fileIndividuals;
foreach(单个1中的键值对kvpInd)
{
foreach(单个2中的键值对kvpInd2)
{
if(kvpInd.Value.name.name==kvpInd2.Value.name.name)
{
添加(kvpInd.Key,kvpInd.Value);
}
}
}
我得到的错误是“已经添加了具有相同密钥的项。”
我有点明白为什么,但我不知道如何以不同的方式让它发挥作用。有人能帮忙吗
谢谢这里的问题是,您对不同
字典
实例中的键和值之间的关系有一个错误的假设。多个条目很可能有不同的键,但值相同。如果在\u Individuals2
中发生这种情况,那么您将在字典中添加两次相同的键。考虑
Map1
- 关键1,价值狗
- 关键2,价值狗
- 关键3,价值狗
// 1:Dog matches 2:Dog
similarInds.Add(1, "Dog");
// 1:Dog matches 3:Dog
similarInds.Add(1, "Dog");
这里您似乎只想知道两个贴图之间相似的单个对象集。如果是这样,则只需存储该值并使用设置
,以防止重复
var similarInds = new HashSet<Individual>();
...
similarInds.Add(kvpInd.Value);
var similarInds=new HashSet();
...
similarInds.Add(kvpInd.Value);
词典中可以有多个值相同的条目。您没有检查或比较钥匙
因此,在_Individuals2中有多个条目具有相同的值,尽管它们具有不同的键
我不知道您在这里做什么,但我认为您的键应该是使每个对象唯一的键,它们不应该真正比较值。如果你使用一个列表或类似的东西,你可以使用交集方法来返回它们的共同点
或者你可以用
_Individuals1.Values.Intersect(_Individuals2.Values);
此外,在处理泛型时,覆盖泛型中存储的对象的相等运算符几乎总是值得的。那么你就不必做这样的事情:
if (kvpInd.Value.name.name == kvpInd2.Value.name.name)
以下是使用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);
让我们后退一步。您有两个字典,可以将个人设置为整数。但是,您不是在比较相关字典的键,而是比较它们的值。这让我觉得钥匙不是唯一的
听起来您想要的是两个词典的完整外部联接:
- 如果某个人仅出现在文件1中,请使用文件1中该个人的键和值
- 同上,仅适用于文件2中的个人
- 如果两个文件包含相同的个人(按名称),则合并记录
这可以通过一些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);
这将安全地使用来自_Individuals2的密钥,只要密钥不是重复的,因此应该使用来自_Individuals2的一些(但可能不是全部)密钥。这是否“更好”取决于具体情况。当name.name
有多个点击时会发生什么?似乎intersect方法效果最好:)谢谢!l.Value.Name==r.Value.Name上的_Individuals2中的行join r上有错误:(我认为它不喜欢r.Value.name partEdited;您必须使用关键字equals
,而不是=
运算符。连接条件的规范不是一个表达式;它定义了两个枚举的投影,在比较时必须相等。如果您查看找到更清晰的场景;您需要提供两个lambda,返回“内部键”和“外部键”。我不喜欢尝试var similarInds=new Set();显然Set不喜欢exist@user1290653对不起,应该是HashSet
。更新了我的答案,然后如何将其创建到列表框的数据源中(lstIndividuals.DataSource)@user1290653要将其放入列表框中,您可能需要首先通过.ToList()
@user1290653将其转换回列表
,但您希望新字典中的键是什么?
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;
}