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 a
Dictionary<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
Why Does "Abcd".Startswith("") Return True
C# "Parameter Is Not Valid." Creating New Bitmap
Using Side-By-Side Assemblies to Load the X64 or X32 Version of a Dll
Order of Event Handler Execution
.Net Hashtable VS Dictionary - Can the Dictionary Be as Fast
Operator Overloading with C# Extension Methods
C#: List All Classes in Assembly
C#: Class for Decoding Quoted-Printable Encoding
What Is the Equivalent of the Java Bigdecimal Class in C#
How to Get the Computer Name in .Net
How to Handle Key Press Event in Console Application
Return View as String in .Net Core
How to Sort Strings Alphabetically While Accounting for Value When a String Is Numeric
Open Image from File, Then Release Lock