combining (custom) lists in C# in a readable, elegant way.

Hello, I have been googling for a good solution to combine multiple lists in c#. I have not come across anything that is remotely readable or simple. And I’m starting to get worried that such elegant way is not possible…

List<CustomItem<int>> CustomItemAList = new List<CustomItem<int>>() {
  new CustomItem<int>("Some string", 0),
  new CustomItem<int>("some other string", 7)
};

List<CustomItem<int>> CustomItemBList = new List<CustomItem<int>>() {
  new CustomItem<int>("Hello", 1337),
  new CustomItem<int>("world", 1234)
};

List<CustomItem<int>> AllCustomItems = ???

foreach(CustomItem<int>> in /* multiple lists? */)

I tried:

List<CustomItem<int>> AllCustomItems = CustomItemAList.Concat(CustomItemBList);

But get the error: ‘List<CustomItem>’ does not contain a definition for ‘Concat’ and no accessible extension method ‘Concat’ accepting a first argument of type ‘List<CloudSaveItem>’ could be found (are you missing a using directive or an assembly reference?).

in javascript i would do something like this:

const all = [...CustomItemAList, ...CustomItemBList];

or:

const all = [].concat(CustomItemAList).concat(CustomItemBList)

Some help would be appreciated

Lists have a .AddRange method for adding collections to the… collection.

3 Likes
var AllCustomItems = List<CustomItem<int>>();
AllCustomItems.AddRange(CustomItemAList);
AllCustomItems.AddRange(CustomItemBList);
1 Like

Thanks a lot both! This is definitely much better than everything I found on SO and google :slight_smile:

1 Like

And if you don’t actually want to add them all together but just want to consider them as a single collection, you can write your own IEnumerable method.

IEnumerable<CustomItem> AllCustomItems()
{
 foreach( var item in CustomItemAList)
 {
   yield return item;
 }
 foreach( var item in CustomItemBList)
 {
   yield return item;
 }
}

Then using it is as simple as:

// consider ALL items in A and B:
foreach( var item in AllCustomItems())
{
}

You can even make AllCustomItems accept a params array of collections to iterate!

SUPER powerful way to process collections.

And Linq has even more, but I prefer to just write explicit code because I find it easier to debug.

4 Likes

Thanks! this is also very elegant and nicely readable :slight_smile:
Regarding the Linq lib you are mentioning - I think i came across some “Concat(listA, listB, listC)” function from linq on stack overfrlow, but i never managed to use it in Unity. I believe i added “using System.linq” or something like that but that wasn’t right. Could you maybe tell me what I need to do to use the linq functions ? :slight_smile:

Personally I wouldn’t bother with Linq for this. Linq is great if you want to make the syntax for doing stuff like adding conditional expressions to selections of items such as ensuring there’s no duplicates and/or having the resultant list ordered in a specific way. In the end, it’s syntactic sugar only. It can also produce a lot of garbage collection overhead depending what you’re doing.

“using System.Linq” is sufficient for most things yes.

Mostly it’s working with IEnumerable so “var result = ListA.ConCat(ListB).ToList()” sort of thing. The “ToList” or “ToArray” is needed because the result is another IEnumerable so if you specifically want the list functionality then you need to create a list.

Avoiding creating a new list as a result is good which is what Kurt was doing above in his “explicit sort of Linq” set-up. :slight_smile: If that waste doesn’t matter then have at it!

2 Likes

Well, adding the namespace using System.Linq; at the top should be enough.
Though this namespace mainly contains classes with extension methods. So you usually have to call those methods on a collection / list / array. C# does not have the concept of standalone methods. Methods are always part of a class / struct / type. So you can not have a global static method.

There is the Concat method which does what you want. As you can see it’s an extension method that is defined in the class Enumerable in the System.Linq namespace. You can use it like this:

var listAll = listA.Concat(listB).Concat(listC).ToList();

This would create 2 IEnumerables which take care of concatting the elements of the 3 lists and in the end we create a new list out of that new collection.

Since Concat is an extension method, the above line actually reads like this:

var listAll = Enumerable.ToList(Enumerable.Concat(Enumerable.Concat(listA, ListB), listC));

I also tend to avoid linq because of the lacking control of garbage.

2 Likes

This ^ ^ ^ ^

My personal feeling is that Linq obfuscates code.

Regardless if that is true, if you cannot write the looping code long-hand (and I mean instantly and right off the top of your head, no hesitation, just bip-bip-bip write the code the way I did above), then you have NO BUSINESS trying to do it in Linq.

You have to understand your problem first. Linq will NOT help you understand any problem.

Alright, good! that concludes it for me :wink: