22

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?

3
  • 6
    Which key do you want to keep? "1", "2", or none? Commented Sep 22, 2009 at 19:30
  • 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? Commented Sep 22, 2009 at 19:31
  • http://www.codeproject.com/KB/linq/Unique.aspx Commented Sep 22, 2009 at 20:13

8 Answers 8

51

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);
Sign up to request clarification or add additional context in comments.

8 Comments

Little does he know after 100K it loops back to 0, ruuhaha
Thanks. The linq solution is what I was looking for. Curious could you somehow use the Distinct extension method?
@User: I don't think Distinct would help in this case... DistinctBy from MoreLINQ would though.
The LINQ method does not work in all situtions. Some dictionary sets do not allow you to call the .GroupBy() method.
@Mitchell: Could you give more details? What do you mean by "dictionary sets"?
|
9

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.

4 Comments

I tried to imagine linq-like solution but didn't have VS at my fingertips. +1 for materializing this approach ;-)
Didn't compile because I missed .Value after the First() call, but fixed it.
This didn't work for me. It created a dictionary with the "value" as both the key and the value.
This produces a dictionary with the values as key and value! :-(
3

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

Comments

1
foreach (var key in mydict.Keys)
  tempdict[mydict[key]] = key;
foreach (var value in tempdict.Keys)
  uniquedict[tempdict[value]] = value;

Comments

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

Comments

1

This is how I did it:

                dictionary.add(control, "string1");
                dictionary.add(control, "string1");
                dictionary.add(control, "string2");
              int x = 0;
        for (int i = 0; i < dictionary.Count; i++)
        {         
            if (dictionary.ElementAt(i).Value == valu)
            {
                x++;
            }
            if (x > 1)
            {
                dictionary.Remove(control);
            }
        }

Comments

0

In addition to the answer of Jon Skeet , if your value is an intern object you can use :

var uniqueValues = myDict.GroupBy(pair => pair.Value.Property)
                     .Select(group => group.First())
                     .ToDictionary(pair => pair.Key, pair => pair.Value);

This way you will remove the duplicate only on one property of the object

Comments

0

Just a footnote to those using the Revit API, this is one method that works for me in removing duplicate elements, when you can't use say wallType as your object type and instead need to leverage raw elements. it's a beaut mate.

  //Add Pair.value to known values HashSet
                 HashSet<string> knownValues = new HashSet<string>();

                Dictionary<Wall, string> uniqueValues = new Dictionary<Wall, string>();

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.