Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

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

Discussion in 'Scripting' started by rpuls, Sep 1, 2022.

  1. rpuls

    rpuls

    Joined:
    Feb 3, 2017
    Posts:
    101
    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...


    Code (CSharp):
    1. List<CustomItem<int>> CustomItemAList = new List<CustomItem<int>>() {
    2.   new CustomItem<int>("Some string", 0),
    3.   new CustomItem<int>("some other string", 7)
    4. };
    5.  
    6. List<CustomItem<int>> CustomItemBList = new List<CustomItem<int>>() {
    7.   new CustomItem<int>("Hello", 1337),
    8.   new CustomItem<int>("world", 1234)
    9. };
    10.  
    11. List<CustomItem<int>> AllCustomItems = ???
    12.  
    13. foreach(CustomItem<int>> in /* multiple lists? */)
    I tried:

    Code (CSharp):
    1. List<CustomItem<int>> AllCustomItems = CustomItemAList.Concat(CustomItemBList);
    But get the error: 'List<CustomItem<int>>' does not contain a definition for 'Concat' and no accessible extension method 'Concat' accepting a first argument of type 'List<CloudSaveItem<int>>' could be found (are you missing a using directive or an assembly reference?).

    in javascript i would do something like this:
    Code (JavaScript):
    1. const all = [...CustomItemAList, ...CustomItemBList];
    2.  
    3. or:
    4.  
    5. const all = [].concat(CustomItemAList).concat(CustomItemBList)
    Some help would be appreciated
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    6,015
    Lists have a .AddRange method for adding collections to the... collection.
     
    rpuls, Bunny83 and MelvMay like this.
  3. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,623
    Bunny83 likes this.
  4. rpuls

    rpuls

    Joined:
    Feb 3, 2017
    Posts:
    101
    MelvMay likes this.
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,966
    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.

    Code (csharp):
    1. IEnumerable<CustomItem> AllCustomItems()
    2. {
    3.  foreach( var item in CustomItemAList)
    4.  {
    5.    yield return item;
    6.  }
    7.  foreach( var item in CustomItemBList)
    8.  {
    9.    yield return item;
    10.  }
    11. }
    Then using it is as simple as:

    Code (csharp):
    1. // consider ALL items in A and B:
    2. foreach( var item in AllCustomItems())
    3. {
    4. }
    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.
     
  6. rpuls

    rpuls

    Joined:
    Feb 3, 2017
    Posts:
    101
    Thanks! this is also very elegant and nicely readable :)
    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 ? :)
     
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,623
    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. :) If that waste doesn't matter then have at it!
     
    rpuls and Bunny83 like this.
  8. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,572
    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:

    Code (CSharp):
    1. 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:

    Code (CSharp):
    1. var listAll = Enumerable.ToList(Enumerable.Concat(Enumerable.Concat(listA, ListB), listC));
    I also tend to avoid linq because of the lacking control of garbage.
     
    rpuls and MelvMay like this.
  9. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,966
    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.
     
  10. rpuls

    rpuls

    Joined:
    Feb 3, 2017
    Posts:
    101
    Alright, good! that concludes it for me ;)