3

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

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Thorin Oakenshield
  • 14,232
  • 33
  • 106
  • 146
  • When the keys match in both the dictionaries, you want to store the value in the first dictionary as you have done for F, 6 ? – Santhosh Sep 03 '10 at 09:10
  • yes. if both the dictionaries having same key value pair then i need to store the the key value pair from the first dictionary – Thorin Oakenshield Sep 03 '10 at 09:12
  • 2
    You need to specify the collision-resolution rules more precisely. – Ani Sep 03 '10 at 09:13

4 Answers4

2

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
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • @ 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 – Thorin Oakenshield Sep 03 '10 at 09:20
  • @Pramodh: See my answer where distinct takes place – abatishchev Sep 03 '10 at 09:37
  • Jon, could you please describe what for `ToLookup()` have you used? – abatishchev Sep 03 '10 at 09:46
  • @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 Sep 03 '10 at 09:47
  • @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 Sep 03 '10 at 09:48
  • 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" – Thorin Oakenshield Sep 03 '10 at 10:20
  • i got a solution from ur answer (http://stackoverflow.com/questions/1462101/c-remove-duplicate-values-from-dictionary). Thank you – Thorin Oakenshield Sep 03 '10 at 10:22
  • 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); – Thorin Oakenshield Sep 03 '10 at 10:23
  • @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 Sep 03 '10 at 10:25
  • oh sorry... not Z,X, I.... only I. F and I have same values. i need to remove I from the "dictionary". – Thorin Oakenshield Sep 03 '10 at 10:29
  • @Pramodh: So why remove I rather than F? Don't forget that a dictionary isn't inherently ordered... – Jon Skeet Sep 03 '10 at 10:37
  • @ 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" } – Thorin Oakenshield Sep 03 '10 at 10:54
  • @Pramodh: What if one dictionary has the same value for two keys which aren't in the other dictionary? – Jon Skeet Sep 03 '10 at 11:03
  • @ Jon Skeet: in that case too i need to keep only the first value – Thorin Oakenshield Sep 03 '10 at 11:05
  • @Pramodh: There's no such concept as "first" in a dictionary. It's an *unordered* collection of key/value pairs. – Jon Skeet Sep 03 '10 at 11:26
  • @ Jon Skeet : i meant the first entry. and i din't know that dictionary is an Unordered collection. Thank you – Thorin Oakenshield Sep 03 '10 at 11:54
1
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
  • 111,048
  • 26
  • 262
  • 307
1

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
  • 142,018
  • 20
  • 234
  • 287
1
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
  • 98,240
  • 88
  • 296
  • 433