Enrico
Enrico

Reputation: 2037

Combine two list of lists in LINQ

I have two lists of the following class:

public class KeyValues
{
    public int Key { get;set;}
    public List<double> DoubleList { get;set;}
}

var list1 = new List<KeyValues>();
list1.Add (new KeyValues(){Key = 33, DoubleList  = new List<double>(){2.3,2.4,2.5}});
list1.Add (new KeyValues(){Key = 34, DoubleList  = new List<double>(){3.3,3.4,3.5}});
list1.Add (new KeyValues(){Key = 35, DoubleList  = new List<double>(){4.3,4.4,4.5}});

var list2 = new List<KeyValues>();
list2.Add (new KeyValues(){Key = 33, DoubleList  = new List<double>(){20.3,20.4}});
list2.Add (new KeyValues(){Key = 34, DoubleList  = new List<double>(){30.3,30.4}});
list2.Add (new KeyValues(){Key = 35, DoubleList  = new List<double>(){40.3,40.4}});

I would like to combine those into a new list by mathing the keys and combining the sub lists. So the result should be:

   list3 = [
                [33, {2.3,2.4,2.5,20.3,20.4}]
                [34, {3.3,3.4,3.5,30.3,30.4}]
                [35, {4.3,4.4,4.5,40.3,40.4}]
            ]

Of course I can iterate over the keys, but isn't there a much better (faster) linq solution for this?

Upvotes: 1

Views: 2884

Answers (4)

Arsen Khachaturyan
Arsen Khachaturyan

Reputation: 8360

My first suggestion here is to use Dicitionary<int, List<double>> instead of creating a class KeyValues or if you want specifically to use Key-Value pair, then .net have that too, it's called: KeyValuePair.

Just in case if you are interested, here is the way to convert your class to Dictionary:

var list3 = list1.Concat(list2)
                 .ToDictionary(item => item.Key);

Note: this will actually fail because of key duplications, so in case if you don't want that to happen, make sure that Keys are different.

Update:
Or you can use Lookup<TKey, TElement> to make it work even with duplicate keys:

var list3 = list1
    .Concat(list2)
    .ToLookup(group => group.Key, group => group.DoubleList)
    .ToDictionary(group => group.Key, group => group.First());

One suggestion: you can use a collection initializer instead of adding elements one by one:

var list1 = new List<KeyValues>
{
    new KeyValues {Key = 33, DoubleList = new List<double>() {2.3, 2.4, 2.5}},
    new KeyValues {Key = 34, DoubleList = new List<double>() {3.3, 3.4, 3.5}},
    new KeyValues {Key = 35, DoubleList = new List<double>() {4.3, 4.4, 4.5}}
};

More information:

  • Dictionary<TKey,TValue> (official documentation here)
  • KeyValuePair VS DictionaryEntry (great post here)

Upvotes: 1

Pavel Anikhouski
Pavel Anikhouski

Reputation: 23298

Using Concat and GroupBy methods can produce the expected result (after making a code compile, of course)

var result = list1.Concat(list2).GroupBy(kv => kv.Key, kv => kv.DoubleList)
    .Select(g => new KeyValues { Key = g.Key, DoubleList = g.SelectMany(i => i).ToList() });

Upvotes: 3

andy meissner
andy meissner

Reputation: 1322

You're example is not syntactically correct: Should be like this:

    var list1 = new List<KeyValue>();
    list1.Add(new KeyValue { Key = 33, DoubleList = new List<double>() { 2.3, 2.4, 2.5 } });
    list1.Add(new KeyValue { Key = 34, DoubleList = new List<double>() { 3.3, 3.4, 3.5 } });
    list1.Add(new KeyValue { Key = 35, DoubleList = new List<double>() { 4.3, 4.4, 4.5 } });

    var list2 = new List<KeyValue>();
    list2.Add(new KeyValue { Key = 33, DoubleList = new List<double>() { 20.3, 20.4 } });
    list2.Add(new KeyValue { Key = 34, DoubleList = new List<double>() { 30.3, 30.4 } });
    list2.Add(new KeyValue { Key = 35, DoubleList = new List<double>() { 40.3, 40.4 } });

    list1.Zip(list2, (first, second) => (first.Key, first.DoubleList.Concat(second.DoubleList));

If the lists have the same element keys in the same order you can do this:

        list1.Zip(list2, (first, second) => 
                 (first.Key, first.DoubleList.Concat(second.DoubleList)));

Upvotes: 1

DavidG
DavidG

Reputation: 119186

You can concatenate the two lists together and then use GroupBy, and then Select to project the output into the desired format. For example:

var list3 = list1.Concat(list2)
    .GroupBy(x => x.Key)
    .Select(x => new KeyValue 
    {
        Key = x.Key, 
        DoubleList = x.SelectMany(x => x.DoubleList).ToList()
    })
    .ToList();

Upvotes: 1

Related Questions