2

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?

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
s.k.paul
  • 7,099
  • 28
  • 93
  • 168

5 Answers5

7

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);
Peter B
  • 22,460
  • 5
  • 32
  • 69
  • No need for the cast - given that it's a `KeyValuePair>`, the type of `Value` is already `List`. (The cast in the OP's original code is superfluous too.) – Jon Skeet Jan 09 '17 at 08:49
  • Yeah, I didn't focus on the type first but I saw it as you were responding. It's in there now. – Peter B Jan 09 '17 at 08:51
  • An additional hint: `Concat` is a LINQ extension method and all these methods use the `List` as a data source, but do not change the original collection. The mentioned `AddRange` is a normal `List`-method like `Add` and `Remove` and therefor alters the collection. – Lukas Körfer Jan 09 '17 at 08:54
7

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.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
4

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();
3

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);
}
Community
  • 1
  • 1
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
1

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.

  • That would have to be `finalList = finalList.Concat(ListFromDict).ToList()`, because Concat returns an `IEnumerable` of the source type, so it cannot be assigned to a list directly. – Peter B Jan 09 '17 at 09:01