views:

1500

answers:

7

How can I create a dictionary with no duplicate values from a dictionary that may have duplicate values?

IDictionary<string, string> myDict = new Dictionary<string, string>();

myDict.Add("1", "blue");
myDict.Add("2", "blue");
myDict.Add("3", "red");
myDict.Add("4", "green");


uniqueValueDict = myDict.???

Edit:

-I don't care which key is kept. - Is there something using Distinct() operation?

A: 

I think you need to give more information about the behavior of the unique-making function. For blue, which key should it keep, 1 or 2?

Tesserex
+18  A: 

What do you want to do with the duplicates? If you don't mind which key you lose, just build another dictionary like this:

IDictionary<string, string> myDict = new Dictionary<string, string>();

myDict.Add("1", "blue");
myDict.Add("2", "blue");
myDict.Add("3", "red");
myDict.Add("4", "green");

HashSet<string> knownValues = new HashSet<string>();
Dictionary<string, string> uniqueValues = new Dictionary<string, string>();

foreach (var pair in myDict)
{
    if (knownValues.Add(pair.Value))
    {
        uniqueValues.Add(pair.Key, pair.Value);
    }
}

That assumes you're using .NET 3.5, admittedly. Let me know if you need a .NET 2.0 solution.

Here's a LINQ-based solution which I find pleasantly compact...

var uniqueValues = myDict.GroupBy(pair => pair.Value)
                         .Select(group => group.First())
                         .ToDictionary(pair => pair.Key, pair => pair.Value);
Jon Skeet
Wow Jon, you almost broke the 100K mark :-)
Eric J.
Little does he know after 100K it loops back to 0, ruuhaha
SwDevMan81
Thanks. The linq solution is what I was looking for. Curious could you somehow use the Distinct extension method?
User
@User: I don't think Distinct would help in this case... DistinctBy from MoreLINQ would though.
Jon Skeet
The LINQ method does not work in all situtions. Some dictionary sets do not allow you to call the .GroupBy() method.
Mitchell Skurnik
@Mitchell: Could you give more details? What do you mean by "dictionary sets"?
Jon Skeet
@Jon I am not sure exactly. I am pulling a ObservableCollection from nested usercontrol and it does not allow me to use .Distinct or .Select and so on. I even tried converting that to a Dictionary/IDictionary and then trying to get the distinct. This still didnt work. I ended up doing a foreach loop on each item and then using the hashset to get detect if it is a duplicate. I then created the new comboboxitems (silverlight project) and added them to the combobox. This was .Net 4/Silverlight 4. While the LINQ method would have been ideal, I am just lucky that your other method worked out
Mitchell Skurnik
@Mitchell: There are various reasons for this, but it's hard to delve into them in comments. Please start a new question, and give more details. For example, make sure that you've got a reference to System.Core.dll, and a using directive for System.Linq. Also, is this the generic `ObservableCollection<T>` or a nongeneric collection?
Jon Skeet
@Jon, yeah...I forgot to reference System.Linq. I should have known better. Thank you for your assistance!
Mitchell Skurnik
+1  A: 
foreach (var key in mydict.Keys)
  tempdict[mydict[key]] = key;
foreach (var value in tempdict.Keys)
  uniquedict[tempdict[value]] = value;
queen3
+5  A: 

The brute-force solution would be something like the following

var result = dictionary
    .GroupBy(kvp => kvp.Value)
    .ToDictionary(grp => grp.First().Value, grp.Key)

assuming you don't really care about the key used to represent a group of duplicates and it is acceptable to rebuild the dictionary.

Daniel Brückner
I tried to imagine linq-like solution but didn't have VS at my fingertips. +1 for materializing this approach ;-)
queen3
I am not sure if it even compiles ... just going to fire up VS and test it...
Daniel Brückner
Didn't compile because I missed .Value after the First() call, but fixed it.
Daniel Brückner
This didn't work for me. It created a dictionary with the "value" as both the key and the value.
User
+1  A: 
Dictionary<string, string> test = new Dictionary<string,string>();
test.Add("1", "blue");
test.Add("2", "blue");
test.Add("3", "green");
test.Add("4", "red");
Dictionary<string, string> test2 = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> entry in test)
{
    if (!test2.ContainsValue(entry.Value))
        test2.Add(entry.Key, entry.Value);
}
Sivvy
+3  A: 

Jon beat me to the .NET 3.5 solution, but this should work if you need a .NET 2.0 solution:

        List<string> vals = new List<string>();
        Dictionary<string, string> newDict = new Dictionary<string, string>();
        foreach (KeyValuePair<string, string> item in myDict)
        {
            if (!vals.Contains(item.Value))
            {
                newDict.Add(item.Key, item.Value);
                vals.Add(item.Value);
            }
        }
Timothy Carter