Lists of lists are WEIRD

I have this list:

public List<List<int>> ExampleList = new List<List<int>>();
ExampleList [0].Add(0);
// Note: every list will have 4 indexes.


You may think that the list will look like this:
[0] - count: 1
+[0] - 0
[1] - null count: 0
[2] - null count: 0
[3] - null count: 0
But no, it looks like this:
[0] - count: 1
+[0] - 0
[1] - count: 1
+[0] - 0
[2] - count: 1
+[0] - 0
[3] - count: 1
+[0] - 0
The command did it for ALL the indexes.
And so I tried to do this:

public List<List<int>> ExampleList = new List<List<int>>();
public List<int> ExampleListHelper = new List<int>();
ExampleListHelper.Add(0);
ExampleList.Add(ExampleListHelper);
//Now I want to do the next index.
ExampleListHelper.Clear();
ExampleListHelper.Add(1);
ExampleList.Add(ExampleListHelper);

Not only it is very annoying, it does not work.
The index [0] of the list in [0] does not store the int 0, but the list ExampleListHelper.
meaning that after the line 4, it looked like this
[0] - count: 1
+[0] - 0
[1] - null count: 0
[2] - null count: 0
[3] - null count: 0
But after the line 7, where I changed the ExampleListHelper’s [0] index from 0 to 1, the list will look like this:
[0] - count: 1
+[0] - 1
[1] - null count: 0
[2] - null count: 0
[3] - null count: 0
Which is VERY annoying because I never touched the [0] index after line 4, but it changed on its own. And so I do this:

public List<List<int>> ExampleList = new List<List<int>>();
public List<int> ExampleListHelper0 = new List<int>();
public List<int> ExampleListHelper1 = new List<int>();
public List<int> ExampleListHelper2 = new List<int>();
public List<int> ExampleListHelper3 = new List<int>();
ExampleListHelper0.Add(0);
ExampleList.Add(ExampleListHelper0);
//Now I want to do the next index.
ExampleListHelper1.Add(1);
ExampleList.Add(ExampleListHelper1);
//  I have tried with List<int>[], and it is still the same.

Then, and ONLY then, it works. But making 4 variables for one variable, and sometimes more if ExampleList has mire than 4 indexes, and if you don’t plan for the ExampleList to have a max of the amount of indexes, it will be impossible.
What can I do?

Not really weird. The outer list is a collection of lists. You can add/remove other List<int> instances to it. Eg: .Add(new List<int>());.

Then to use any of the inner lists, you access it via the outer list.

Though none of your code or examples make much sense/is valid code. I’m not sure what you’re exactly asking here. Also worth noting that Unity cannot serialise these kinds of collections.

2 Likes

I have started to write, but then I accidently posted it… and so I edited it, so you didn’t see the full post…

What you’re encountering is just the behaviour of reference type values. Classes are reference types. Your variables for reference types are actually pointers to it’s location in memory.

In your first code example, you are adding the same reference to the same inner list twice, which is why you get the ‘odd’ behaviour. However it is expected behaviour for reference types. The outer list has two references to the same inner list. Ergo, two pointers to the same location in memory.

Which is why the second example works, because you are correctly adding four new, separate instances of a List<int>.

So nothing to do with collections at all, honestly. Just to do with a fundamental aspect of C#.

Needless to say, when dealing with collections, you should familiarise yourself with loops. As the two concepts heavily use one another.

4 Likes

But if I use loops, I will still need to have 4 different variables.
Thanks, so what I did in the final example was the best solution.
Out of curiosity, what if I have an un-defined list length? In my example(and my actual code)
I need 4 indexes, but what if I need an un-defined amount?
I understand why the second example does not work:

public List<List<int>> ExampleList = new List<List<int>>();
public List<int> ExampleListHelper = new List<int>();
ExampleListHelper.Add(0);
ExampleList.Add(ExampleListHelper);
//Now I want to do the next index.
ExampleListHelper.Clear();
ExampleListHelper.Add(1);
ExampleList.Add(ExampleListHelper);

but I didn’t quite understand why the first example does not work:

public List<List<int>> ExampleList = new List<List<int>>();
ExampleList [0].Add(0);
// Note: every list will have 4 indexes.

You really should just do some reading on reference types: Reference types - C# reference | Microsoft Learn

It’s about as fundamental an aspect of C# as you can get. You will find it very hard to use C# without understanding this facet of the language.

None of what you said has any bearing on the fact a List is a reference type. An ‘undefined length’ changes nothing.

3 Likes

Well, your first example doesn’t work because you only created one list, the outer list that is supposed to store other lists in their elements. When you do

ExampleList [0].Add(0);

your ExampleList is actually empty. It doesn’t have an element with index 0. You would have to do

ExampleList.Add(new List<int>());
ExampleList [0].Add(0);

As it was already explained by Spiney, you have to create your nested lists at some point. Just accessing an element does not magically create an instance of a class or add an element to a list.

So if your outer list should contain 4 child / nested lists, you have to create those 4 list objects yourself. Of course you can do that in a loop as well

for(int i = 0; i < 4; i++)
    ExampleList.Add(new List<int>());
ExampleList [0].Add(0);
ExampleList [2].Add(42);
ExampleList [3].Add(101);
2 Likes

I know I have to firstly create 4 indexes. In the example I firstly created the inexses. If I do what you said, which I did at the start, it will not work.

I’m not sure you understand what my code does. The importent part is to create 4 separate List instances which I did in a loop and add each new list to the outer list. So each of the 4 slots in the outer list contains a separate List object. Once you have that, you can interact with those instances through the 4 indices. I also have the feeling that you may need some general C# course if this is confuses you. We explained it a couple of times now and we can not teach absolute C# basics here.

1 Like

Perhaps I’m wrong but I think you’re having trouble differentiating between arrays and lists.
A new list is just an empty instance, without any elements.

It doesn’t work the same as arrays do, because the arrays allocate all of their elements when instantiated (and initialize to default values depending on the type).

When you instantiate a list you ought to add the elements to it. Whether that element is another list instance, or some other value or reference it doesn’t matter.

Arrays and lists are very different in how they operate. Lists are much more, let’s say, user friendly, because you don’t have to consider their pre-allocated size, and they will resize on their own, which isn’t how arrays are typically used.

That said, arrays are more fundamental and important for language-wise representation of data in series. Lists are built on top of arrays to provide flexibility and act as a useful collection that is list-like in behavior, i.e. you can freely add, find, or remove the elements, and can also randomly access the stored elements. In fact the latter behavior is the only thing that resembles arrays.

With arrays you can’t freely add or remove, their size is fixed, imagine it like a block of little boxes which have to be filled in, or else they contain default values (or nulls for reference types).

This is why indexer [0] works with instantiated arrays (of size 1 or greater), but doesn’t work with lists, at least not immediately. You can’t index an element that is out of range, the following must be true 0 <= index && index < list.Count, however because the arrays have a fixed size (called Length) you just make sure that index < array.Length whereas the list starts with a Count of 0.

1 Like

Sorry, my code wasn’t exactly the same, but it was EXTRIMLY similar.
I did this:

List<int> EmptyList = new List<int>();
for(int i = 0; i < 4; i++)
    ExampleList.Add(new List<EmptyList>());

This does not work.
Maybe it is because the index stores “emptyList” and changing the index, also changes “emptyList”,
and so it changes the other indexes.
Thank you, and I’ll read it tommorow.

It is not similar, you’re violating the basic principles of programming in C# by using identifiers in a chaotic manner.

In your example, EmptyList is a variable identifier, not a variable type. When you declare a list it expects a valid element type inside < and >

You honestly need to learn C# better and, because this is not specific to C#, what programming is in general. What it expects, how it works and runs. You can’t make mistakes of this magnitude in code, and in this case you’re violating the most basic of rules (aka the syntax itself). That means what you wrote has no meaningful result and the system wasn’t designed to interpret this at all – i.e. read your mind.

If you’re having trouble with syntax errors, that’s a sure sign you need to take it slowly, and get a better understanding of what syntax even means, before you attempt to tackle anything more complicated.

4 Likes