Duplicate Keys in .Net Dictionaries

Duplicate keys in .NET dictionaries?

If you're using .NET 3.5, use the Lookup class.

EDIT: You generally create a Lookup using Enumerable.ToLookup. This does assume that you don't need to change it afterwards - but I typically find that's good enough.

If that doesn't work for you, I don't think there's anything in the framework which will help - and using the dictionary is as good as it gets :(

How to add duplicate keys into the Dictionary

how to allow to add duplicate keys in Dictionary

It is not possible. All keys should be unique. As Dictionary<TKey, TValue> implemented:

Every key in aDictionary<TKey, TValue> must be unique according to
the dictionary's equality comparer.

Possible solutions - you can keep collection of strings as value (i.e. use Dictionary<string, List<string>>), or (better) you can use Lookup<TKey, TValue> instead of dictionary.


how to check for duplicate keys and delete previous value from
Dictionary?

You can check if the key exists with previousLines.ContainsKey(dialedno) but if you always want to hold the last line, then just replace whatever dictionary had for the key, or add the new key if it is not in the dictionary:

previousLines[dialedno] = line;

Dictionary with duplicate Key

A Dictionary, by definition, will never be able to have multiple keys with the same value. (If you looked up a key whatever would you return?) Even a Lookup, which you refer to, doesn't allow it. What you can do is have each key refer to multiple values (logically, not technically). This is done by having a dictionary in which the value is a data structure of some sort (for example, a List) that contains all of the values that correspond to that particular key.

Duplicate keys in Dictionary when using PhysicalAddress as the key

Dictionary expects immutable object as a key, with a stable GetHashCode / Equals implementation.
This means that after object is placed into dictionary, value returned by GetHashCode should
not change, and any changes made to this object should not affect Equals method.

Although PhysicalAddress class was designed immutable, it still contains a few extension points,
where its immutability is flawed.

First, it can be changed through input byte array,
which is not copied but passed by reference, like this:

var data = new byte[] { 1,2,3 };
var mac = new PhysicalAddress(data);
data[0] = 0;

Second, PhysicalAddress is not a sealed class, and can be changed by derived
implementation through overriding Constructor / GetHashCode / Equals methods.
But this use case looks more like a hack, so we will ignore it, as well as modifications through reflection.

Your situation can only be achieved by first placing PhysicalAddress object into dictionary,
and then modifying its source byte array, and then wrapping it into new PhysicalAddress instance.

Luckily, PhysicalAddress' GetHashCode implementation computes hash only once,
and if same instance is modified, it is still placed into same dictionary bucket,
and located again by Equals.

But, if source byte array is passed into another instance of PhysicalAddress, where hash
was not yet computed - hash is recomputed for new byte[] value, new bucket is located,
and duplicate is inserted into dictionary. In rare cases, same bucket can be located
from new hash, and again, no duplicate is inserted.

Here's the code which reproduces the problem:

using System;
using System.Collections.Generic;
using System.Net.NetworkInformation;

class App
{
static void Main()
{
var data = new byte[] { 1,2,3,4 };
var mac1 = new PhysicalAddress(data);
var mac2 = new PhysicalAddress(data);
var dictionary = new Dictionary<PhysicalAddress,string>();
dictionary[mac1] = "A";
Console.WriteLine("Has mac1:" + dictionary.ContainsKey(mac1));
//Console.WriteLine("Has mac2:" + dictionary.ContainsKey(mac2));
data[0] = 0;
Console.WriteLine("After modification");
Console.WriteLine("Has mac1:" + dictionary.ContainsKey(mac1));
Console.WriteLine("Has mac2:" + dictionary.ContainsKey(mac2));

dictionary[mac2] = "B";
foreach (var kvp in dictionary)
Console.WriteLine(kvp.Key + "=" + kvp.Value);
}
}

Note the commented line - if we will uncomment it, "ContainsKey" method will precompute hash for mac2, and it will be the same even after modification.

So my recommendation is to locate piece of code which generates PhysicalAddress instances, and create
new byte array copy for each constructor call.

A dictionary with multiple entries with the same key

In .NET 3.5 you can use a Lookup instead of a Dictionary.

var items = new List<KeyValuePair<int, String>>();
items.Add(new KeyValuePair<int, String>(1, "first"));
items.Add(new KeyValuePair<int, String>(1, "second"));
var lookup = items.ToLookup(kvp => kvp.Key, kvp => kvp.Value);

foreach (string x in lookup[1])
{
Console.WriteLine(x);
}

The Lookup class is immutable. If you want a mutable version you can use EditableLookup from MiscUtil.

How to merge two dictionaries but on duplicate keys combine the values in C#?

You could first merge your dictionaries in a IEnumerable<KeyValuePair<string, List<int>>> by combining them with Concat. We do this because some keys may not exist in both dictionaries, and we want them included in the final merged result.

We can then group the keys with ToLookup, then create a final merged Dictionary<string, List<int>> with ToDictionary, ensuring that the inner grouped lists are flattened with SelectMany.

var dictA = new Dictionary<string, List<int>>
{
{ "wow", new List<int>{0,0,0} },
{ "key", new List<int>{1,2,3} }
};

var dictB = new Dictionary<string, List<int>>
{
{ "querty", new List<int>{4,0,4} },
{ "key", new List<int>{4,5,6} }
};

var merged = dictA
.Concat(dictB)
.ToLookup(kvp => kvp.Key, kvp => kvp.Value)
.ToDictionary(group => group.Key, group => group.SelectMany(x => x).ToList());

foreach (var kvp in merged)
{
Console.WriteLine($"{kvp.Key} -> {"{ " + string.Join(", ", kvp.Value) + " }"}");
}

Output:

wow -> { 0, 0, 0 }
key -> { 1, 2, 3, 4, 5, 6 }
querty -> { 4, 0, 4 }

how to add duplicate keys to dictionary string,string

Check out this:

What is the point of Lookup<TKey, TElement>?

You can use the Lookup class to help you create collections with duplicates keys.

Merging dictionaries with duplicate keys producing child dictionaries

You just need a bit of old fashioned recursion. This assumes the structure of the dictionaries are compatible and does no error checking for attempts to merge dictionaries and string values.

    Dictionary<string, object> MergeDictionary(IEnumerable<Dictionary<string, object>> dicts)
{
var l = dicts.SelectMany(d => d).ToLookup(kv => kv.Key, kv => kv.Value);
return l.ToDictionary(
g => g.Key,
g => g.Count() == 1
? g.First()
: MergeDictionary(g.Cast<Dictionary<string, object>>()));
}

To test it you can run this, which returns your desired results.

    static void TestMergeDictionary()
{
var dbx = new Dictionary<string, object> { { "Data_C", "C" } };
var dx = new Dictionary<string, object> { { "Data_B", dbx } };

var dbz = new Dictionary<string, object> { { "Data_F", "F" } };
var dz = new Dictionary<string, object> { { "Data_B", dbz } };

var da = MergeDictionary(new[] { dx, dz });
}

Merge two dictionaries and remove duplicate keys and sort by the value

You can use Concat with sample LINQ to achieve what you want. Here it is:

Dictionary<int, string> result = 
firstDict.Concat(secondDict.Where(kvp => !firstDict.ContainsKey(kvp.Key)))
.OrderBy(c=>c.Value)
.ToDictionary(c => c.Key, c => c.Value);

The result is:

{4, "A"}
{2, "B"}
{1, "X"}


Related Topics



Leave a reply



Submit