views:

108

answers:

4

I have two dictionaries like

Dictionary<String, String> one = new Dictionary<string, string>
{
    { "A", "1" },
    { "B", "2" },
    { "C", "3" },
    { "D", "4" },
    { "E", "5" },
    { "F", "6" },
    { "G", "7" },
    { "H", "8" }
};

Dictionary<String, String> two = new Dictionary<string, string>
{
    { "A", "1" },
    { "B", "2" },
    { "C", "3" },
    { "E", "4" },
    { "F", "4" },
    { "I", "6" },
    { "J", "10" },
    { "K", "11" }
};

i need to merge the two dictionary in key level and then in value level and to add the resulting dictionary into the new dictionary three, the resulting dictionary should not have same keys or same values and in this case the resulting dictionary is like

Dictionary<String, String> three = new Dictionary<string, string>
{
    { "A", "1" },
    { "B", "2" },
    { "C", "3" },
    { "D", "4" },
    { "E", "5" },
    { "F", "6" },
    { "G", "7" },
    { "H", "8" },
    { "J", "10" },
    { "K", "11" }
};

Now i'm using like

  1. Union all the keys in the two dictionaries
  2. Creating a new dictionary with the new keys
  3. removing the dupicate values( same values )

EDIT: if both the dictionaries having same key value pair then i need to store the the key value pair from the first dictionary .

is there any way to do this using LINQ? Thanks in advance

+1  A: 

One option, using the fact that a dictionary is a sequence of key/value pairs:

var dictionary = dictionary1.Concat(dictionary2)
                            .ToLookup(pair => pair.Key, pair => pair.Value)
                            .ToDictionary(x => x.Key, x => x.First());

That's not terribly efficient, admittedly (as it essentially builds up a hash table twice) but I believe it will work.

Jon Skeet
@ Jon Skeet: thank you , i need to remove the duplicate values from "dictionary". As i mentioned, the resulting dictionary should not contain same key or same value
Pramodh
@Pramodh: See my answer where distinct takes place
abatishchev
Jon, could you please describe what for `ToLookup()` have you used?
abatishchev
@abatishchev: It allows there to be multiple entries with the same key. We then just take the first of those values when constructing the dictionary.
Jon Skeet
@Pramodh: What exactly do you mean by "same key or same value"? Please give a concrete example of what you want to happen which my code doesn't satisfy.
Jon Skeet
With the above LINQ the result is like { "A", "1" }, { "B", "2" }, { "C", "3" }, { "D", "4" }, { "E", "5" }, { "F", "6" }, { "G", "7" }, { "Z", "3" }, { "X", "4" }, { "I", "6" }, { "H", "8" }, { "J", "10" }, { "K", "11" } i need to remove the entries of "Z" "X" and "I"
Pramodh
i got a solution from ur answer (http://stackoverflow.com/questions/1462101/c-remove-duplicate-values-from-dictionary). Thank you
Pramodh
The LINQ is like one.Concat(two) .ToLookup(pair => pair.Key, pair => pair.Value) .ToDictionary(x => x.Key, x => x.First()).GroupBy(pair => pair.Value) .Select(group => group.First()) .ToDictionary(pair => pair.Key, pair => pair.Value);
Pramodh
@Pramodh: Where do Z, X and I come in? They're not in your sample source data. Please read http://tinyurl.com/so-hints and think about what readers will need to know when you write questions.
Jon Skeet
oh sorry... not Z,X, I.... only I. F and I have same values. i need to remove I from the "dictionary".
Pramodh
@Pramodh: So why remove I rather than F? Don't forget that a dictionary isn't inherently ordered...
Jon Skeet
@ Jon Skeet : if the both the dictionaries having same keys the i'll keep the first dictionary key.and if both the dictionaries having same values i need to store the value from the first dictionary to the result.the expected answer is like{ "A", "1" }, { "B", "2" }, { "C", "3" }, { "D", "4" }, { "E", "5" }, { "F", "6" }, { "G", "7" }, { "H", "8" }, { "J", "10" }, { "K", "11" }
Pramodh
@Pramodh: What if one dictionary has the same value for two keys which aren't in the other dictionary?
Jon Skeet
@ Jon Skeet: in that case too i need to keep only the first value
Pramodh
@Pramodh: There's no such concept as "first" in a dictionary. It's an *unordered* collection of key/value pairs.
Jon Skeet
@ Jon Skeet : i meant the first entry. and i din't know that dictionary is an Unordered collection. Thank you
Pramodh
+1  A: 
var three = new Dictionary<string, string>();
foreach(var kvp in two.Concat(one))
  three[kvp.Key] = kvp.Value;

This is quite efficient, but I'm not sure if this is the output you want; the problem statement is not clear enough.

EDIT: If you want to subsequently remove duplicate values from three:

var keysWithDuplicateValues = three.ToLookup(kvp => kvp.Value, kvp => kvp.Key)
                                   .SelectMany(group => group.Skip(1))
                                   .ToList();

foreach(var key in keysWithDuplicateValues)
   three.Remove(key);   

Note that this is better than eagerly removing duplicate keys and duplicate values at the start, because some of the collisions may be automatically resolved.

Ani
A: 

A linq-only method would be to concatenate the two dictionaries and fold the resulting sequence of key/values into a single result. This will overwrite the values for any keys in dict2 that are also in dict1:

var dict3 = dict2.Concat(dict1)
    .Aggregate(new Dictionary<string, string>(), (d, kvp) => {
        d[kvp.Key] = kvp.Value;
        return d;
    });
Lee
+1  A: 
class StringKeyValuePairEqualityComparer : IEqualityComparer<KeyValuePair<string, string>>
{
    public bool Equals(KeyValuePair<string, string> x, KeyValuePair<string, string> y)
    {
        return x.Key == y.Key;
    }

    public int GetHashCode(KeyValuePair<string, string> obj)
    {
        return obj.Key.GetHashCode();
    }
}

var three = Enumerable.Concat(one, two)
                .Distinct(new StringKeyValuePairEqualityComparer())
                .ToDictionary(p => p.Key, p => p.Value);

int count = three.Keys.Count; // 11
abatishchev