簡體   English   中英

比較兩個字典並將字典值添加到另一個字典 C#

[英]Comparing two dictionaries and adding dictionary value to another dictionary C#

我正在嘗試比較加載的兩個詞典。每個人都包含一個 ID 和一個個人 object。

到目前為止的代碼是

            _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);
                }
            }
        }

我收到“已添加具有相同鍵的項目”的錯誤。 我有點明白為什么,但我不確定如何 go 以不同的方式讓它工作。 有人可以幫忙嗎?

謝謝

這里的問題是您對不同Dictionary<TKey, TValue>實例中的鍵和值之間的關系有一個錯誤的假設。 多個條目很可能具有不同的鍵但具有相同的值。 如果這種情況發生在_Individuals2中,那么您最終將向字典中添加相同的鍵兩次。 考慮

地圖1

  • 重點一、超值狗

地圖2

  • 關鍵2,超值狗
  • 關鍵3,超值狗

在這種情況下,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);

字典中可以有多個具有相同值的條目。 您沒有做任何事情來檢查或比較密鑰。

因此,您在 _Individuals2 中有多個條目具有相同的值,盡管它們具有不同的鍵。

我不知道你在這里做什么,但我認為你的鑰匙應該是讓每個 object 獨一無二的東西,他們真的不應該比較這些值。 如果您使用列表或類似的東西,您可以只使用 Intersection 方法返回它們的共同點。

或者你可以只使用

_Individuals1.Values.Intersect(_Individuals2.Values);

此外,在使用 generics 時,覆蓋存儲在泛型中的對象的相等運算符幾乎總是值得的。 那么你不必做這樣的事情:

if (kvpInd.Value.name.name == kvpInd2.Value.name.name)

以下是使用 lambda 的方法:

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);

讓我們退后一步。 您有兩個字典,將 Individuals 鍵為 integer。但是,您不是在比較相關字典的鍵,而是比較它們的值。 這讓我覺得鑰匙不是唯一的。

聽起來您想要的是兩個詞典的完整外部連接:

  • 如果個人僅存在於 File1 中,請使用 File1 中個人的鍵和值。
  • 僅適用於 File2 中的個人。
  • 如果兩個文件包含相同的個人(按名稱),則合並記錄。

這可以通過一些 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 中的密鑰,方法是對照合並的目錄檢查每個密鑰。 該代碼如下所示:

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 的一些(但可能不是全部)密鑰。 這是否“更好”取決於具體情況。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM