List<T> Concatenation dynamically

2k views Asked by At

I am trying to concate List<> as follows-

 List<Student> finalList = new List<Student>();
 var sortedDict = dictOfList.OrderBy(k => k.Key);
 foreach (KeyValuePair<int, List<Student>> entry in sortedDict) {          
     List<Student> ListFromDict = (List<Student>)entry.Value;
     finalList.Concat(ListFromDict);
 }

But no concatenation happens. finalList remains empty. Any help?

5

There are 5 answers

3
Peter B On BEST ANSWER

A call to Concat does not modify the original list, instead it returns a new list - or to be totally accurate: it returns an IEnumerable<string> that will produce the contents of both lists concatenated, without modifying either of them.

You probably want to use AddRange which does what you want:

List<Student> ListFromDict = (List<Student>)entry.Value;
finalList.AddRange(ListFromDict);

Or even shorter (in one line of code):

finalList.AddRange((List<Student>)entry.Value);


And because entry.Value is already of type List<Student>, you can use just this:

finalList.AddRange(entry.Value);
1
AudioBubble On

You may want to read up the documentation on Enumerable.Concat:

Return Value
Type: System.Collections.Generic.IEnumerable
An IEnumerable that contains the concatenated elements of the two input sequences.

So you may want to use the return value, which holds the new elements.

As an alternative, you can use List.AddRange, which Adds the elements of the specified collection to the end of the List.

As an aside, you can also achieve your goal with a simple LINQ query:

var finalList = dictOfList.OrderBy(k => k.Key)
                          .SelectMany(k => k.Value)
                          .ToList();
0
willeM_ Van Onsem On

As specified here, Concat generates a new sequence whereas AddRange actually adds the elements to the list. You thus should rewrite it to:

List<Student> finalList = new List<Student>();
var sortedDict = dictOfList.OrderBy(k => k.Key);
foreach (KeyValuePair<int, List<Student>> entry in sortedDict) {          
    List<Student> ListFromDict = (List<Student>)entry.Value;
    finalList.AddRange(ListFromDict);
}

Furthermore you can improve the efficiency a bit, by omitting the cast to a List<T> object since entry.Value is already a List<T> (and technically only needs to be an IEnumerable<T>):

var sortedDict = dictOfList.OrderBy(k => k.Key);
foreach (KeyValuePair<int, List<Student>> entry in sortedDict) {
    finalList.AddRange(entry.Value);
}
1
Oleksandr Kobylianskyi On

Concat method does not modify original collection, instead it returns brand new collection with concatenation result. So, either try finalList = finalList.Concat(ListFromDict) or use AddRange method which modifies target list.

0
Jon Skeet On

Other answers have explained why Concat isn't helping you - but they've all kept your original loop. There's no need for that - LINQ has you covered:

List<Student> finalList = dictOfList.OrderBy(k => k.Key)
                                    .SelectMany(pair => pair.Value)
                                    .ToList();

To be clear, this replaces the whole of your existing code, not just the body of the loop.

Much simpler :) Whenever you find yourself using a foreach loop which does nothing but build another collection, it's worth seeing whether you can eliminate that loop using LINQ.