Denis repon
Denis repon

Reputation: 33

connect values with the same key in Dictionary<string, string>

I need to combine 2 dictionary. they have the same key (KKK) with different values:

Dictionary<string, string> dic1 = ...Load***();
Dictionary<string, string> dic2 = ...Load***();

dic1:

...
[29] {[RCP, 555501001]}
[30] {[KKK, 04611105012042000120]}
...

dic2:

...
[49] {[SUM, 85737]}
[50] {[KKK, 04611701040040000180]}
...

Union:

Dictionary<string, string> dicUnion= dic1.Union(dic2).OrderBy(k => k.Key).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

result:

ThrowArgumentException: The item with the same key has already been added.

I have connect values with the same key in union Dictionary:

...
[29] {[RCP, "555501001"]}
[30] {[KKK, "04611105012042000120 04611701040040000180"]}
[31] {[SUM, "85737"]}
...

Upvotes: 3

Views: 296

Answers (4)

Tim Schmelter
Tim Schmelter

Reputation: 460068

If you really want to use LINQ in this case(i'd prefer a loop):

var dicUnion = dic1.Concat(dic2)
    .GroupBy(kv => kv.Key)
    .ToDictionary(g => g.Key, g => String.Join(" ", g.Select(kv => kv.Value)));

This will merge both dictionaries but don't care about common keys or different values.

I need to combine 2 dictionary, they have the same key (KKK) with different values

Ok, if you only want to create a dictionary of common keys:

var union = from kv1 in dic1
            join kv2 in dic2
            on kv1.Key equals kv2.Key into keyGroup
            where keyGroup.Any()
            select new KeyValuePair<string, string>(kv1.Key, string.Join(" ", keyGroup.Select(kv => kv.Value)));

Dictionary<string, string> dicUnion = union.ToDictionary(kv => kv.Key, kv => kv.Value);

But instead of concatenating values which have the same key in both dictionaries, i'd use a different approach. Use a Lookup<TKey, TValue>. For example:

var keyLookup = dic1.Concat(dic2).ToLookup(kv => kv.Key, kv => kv.Value);

Now you can do wahtever you want with the values, f.e. create a List<string>:

List<string> values = keyLookup["KKK"].ToList();

Upvotes: 4

eXavier
eXavier

Reputation: 4981

If you want to connect ONLY values with the same key, you can use IEnumerable.Join method like this:

var res = dic1.Join(dic2, o1 => o1.Key, o2 => o2.Key, (o1, o2) => new { o1.Key, Value1 = o1.Value, Value2 = o2.Value});

The arguments are the second IEnumerable, key selectors and result selector. In my snippet I create anonymous class but you can create whatever structure you want. The result is again IEnumerable, you can either iterate on or use its ToList(), ToArray(), etc method.

EDIT: after reading comments to other posts I understand you want to get something like this:

dic1.Concat(dic2)
    .ToLookup(o => o.Key, o => o.Value)
    .ToDictionary(o => o.Key, o => string.Join(" ", o.Distinct()))

Upvotes: 0

fubo
fubo

Reputation: 45947

I'd use a simple loop to add / append items

Dictionary<string, string> dicUnion = new Dictionary<string, string>(dic1); 
foreach(var item in dic2)
{
    if(dicUnion.ContainsKey(item.Key))
    {
        dicUnion[item.Key] += " " + item.Value;
    }
    else
    {
        dicUnion.Add(item.Key, item.Value);
    }
}

Upvotes: 4

Emre Kabaoglu
Emre Kabaoglu

Reputation: 13146

Just try like this;

        var intersectedItems = dic1.Where(x => dic2.ContainsKey(x.Key)).Select(x => new
        {
            Key = x.Key,
            Value = x.Value + " " + dic2[x.Key]
        }).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
        var dicUnion = dic1.Where(x => !intersectedItems.ContainsKey(x.Key))
            .Union(dic2.Where(x => !intersectedItems.ContainsKey(x.Key)))
            .Union(intersectedItems).OrderBy(k => k.Key)
            .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

Upvotes: 1

Related Questions