-3

This is driving me crazy. I'm trying to simply increase the size of a list via script.

I've tried to set the List size before I reference it by saying

List<int> listName = new List<int>(20);

but this does not work. Nothing happens. Not even in Awake or Start.

I've tried to increase the size by doing this in a loop:

foreach(var line in table)
{
    int tempInt = new int();
    intList.Add(tempInt);
}

this works and my list size increases.

But my problem is that AFTER increasing this list's size I cannot reference any of the elements created at runtime. I can't reference intList[2] for example.

I've tried doing this in a normal void and IEnumerator and neither work.

All I want to do here is increase my list's size as it is needed and then reference to those list items as needed....

As simple as this problem sounds this is honestly the most annoying coding issue I have ever faced in Unity.

PLEASE help.

EDIT: Here;s the code I'm using...

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using System;

public class DataExtraction : MonoBehaviour
{
    [Header("Tables")]
    public List<DataItem> tables; // The main table that needs to be populated
    
    [Header("Extraction Variables")]
    public string webAddress = "https://old.winningform.co.za/ECP/2F200717_1.htm"; // URL that the data will be extracted from 
    //(note this URL will be deleted after 17 July 2020 
    
    public List<string> rawDataSplit; // Place to store each line of the raw data
    public int currentTable = 0;
    
    void Awake()
    {
        DataItem newDataItem = new DataItem();
        tables.Add(newDataItem);
    }
    
    void Start()
    {
        if(webAddress != "")
        {
            StartCoroutine(GetRequest(webAddress));
        }
    }
    
    IEnumerator GetRequest(string uri)
    {
        using (UnityWebRequest webRequest = UnityWebRequest.Get(uri))
        {
            yield return webRequest.SendWebRequest();

            string[] pages = uri.Split('/');
            int page = pages.Length - 1;

            if (webRequest.isNetworkError)
            {
                Debug.Log(pages[page] + ": Error: " + webRequest.error);
            }
            else
            {
                string rawData = webRequest.downloadHandler.text;
                
                // Splitting the data into lines and assigning it to rawDataSplit list
                var linesInText = rawData.Split('\n'); 
                
                foreach(var line in linesInText)
                {
                    if(line != "")
                    {
                        rawDataSplit.Add(line);
                    }
                }
                //
                
                // Data has been split and assigned to the rawDataSplit list
                AssignTableData();
                //
            }
        }
    }
    
    void AssignTableData()
    {
        foreach(var line in rawDataSplit)
        {
            // When the script finds this line it indicates that a new Table has been found in the text
            // This will create a new table in the list and increase the currentTable number by 1 (to be used as an index number)
            // The following lines of data after that will then be added to THAT table until the next table is found...
            // A new table will again be created and the information will be added there instead.
            if(line.Contains("<table border"))
            {
                currentTable++;
                
                DataItem newDataItem = new DataItem();
                tables.Add(newDataItem);
                
                tables[currentTable].rawTableData.Add(line);
            }
            else // If not found automatically add information into Table index 0 (created at Awake)
            {
                print(tables.Count.ToString());
                tables[currentTable].rawTableData.Add(line);
            }
        }
    }
}

[System.Serializable]
public class DataItem
{
    public List<string> rawTableData;
}

ERROR:

NullReferenceException: Object reference not set to an instance of an object
DataExtraction.AssignTableData () (at Assets/DataExtraction.cs:89)
DataExtraction+<GetRequest>d__6.MoveNext () (at Assets/DataExtraction.cs:63)
UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at C:/buildslave/unity/build/Runtime/Export/Coroutines.cs:17)
Wichael
  • 1
  • 1
  • 3
  • Please provide a minimal reproducible example of this behavior. A List automatically sizes with its contents and you can index them as expected. What are you actually encountering? – JSteward Jul 13 '20 at 18:58
  • Just after the the foreach loop, you should be able to access `intList[i]` where `0 <= i < table.Count`. If you can't then probably you are trying to access another instance of `listName`. Where exactly is `listName` declared? Where is the foreach loop and where are you trying to access the list? – Olivier Jacot-Descombes Jul 13 '20 at 19:19
  • Why do you feel you need to explicitly manage the `List<>`'s size? Much of the advantage of using a `List<>` compared to an array is that you can freely add and remove elements without having to worry about the size of the underlying collection. Did you read the documentation and understand the difference between and implications of the `Count` and `Capacity` properties? – Lance U. Matthews Jul 13 '20 at 19:22
  • @JSteward so I wrote a test script to explain my problem and the script does exactly what it's supposed to do... I'll take another look at this and see if I can some how post an edit with an example of my problem script. – Wichael Jul 13 '20 at 19:24
  • @BACON because I will have a list of classes with lists in them that I need to add data to in order to sort it based on extracted information from an HTML page. There will be words in the data that trigger when to add information into a certain list. In order to do that I need to increase the main list;s size when ever a new table is found in the HTML code. I need to add the information that follows into THAT table number. I edited the main post with an example. – Wichael Jul 13 '20 at 20:09
  • I think this question is confusing not only because you keep mentioning that you want to increase the size of the list — which, really, is just a side-effect of what you really want to do which is _add an item to the list_ — but also because it's not clear what "size" even means: `Count` or `Capacity`? The code that was added doesn't really clear things up because you don't interact with `Count` or `Capacity` anywhere, we don't know which line is throwing the `NullReferenceException`, and the original code snippet clearly doesn't throw the same exception. – Lance U. Matthews Jul 13 '20 at 20:35

3 Answers3

0

Lists should automatically increase in size. Arrays do not. You should not need to set a size of the List, but the idea is that it would help with performance.

The code you mentioned:

foreach(var line in table)
{
    int tempInt = new int();
    intList.Add(tempInt);
}

should effectively add 20 default int's to the list. So they should all be set to 0. Are you somehow overriding your values? How are you setting your actual values? Can you provide more details on how you're adding values to the list, and then how you're using them?

If you're setting values in the editor, in the inspector, then you should be careful not to re-initialize the list as this would wipe out anything coming from the editor. How are you storing this list? It's not clear if you're using a public or private field, or property or something that's being instantiated inside a method.

John
  • 96
  • 4
  • New to this and don't know how to post code in the reply... Basically I'm populating a list with data extracted from an html page into multiple lists. There can be hundreds of these sub lists and I need to be able to increase the list size as needed so I can add information into the next item. I'm able to increase the list size but referencing the item doesn't work. It's like it isn't being recognized in that frame or something... – Wichael Jul 13 '20 at 19:07
  • So to try and write what I'm doing in code without a code format... int tableNumber = -1; foreach(var line in rawData) if(line.Contains("New Table") tableNumber++; Table newTable = new Table(); tables.Add(newTable); Debug.Log(tables[tableNumber].tableItem.ToString()); – Wichael Jul 13 '20 at 19:12
  • Can you post that code in your original question? You must be doing something fundamentally wrong as lists automatically resize and you shouldn't have any issue accessing by index. Update the original question so we can see the problem code in as much detail as possible – Charleh Jul 13 '20 at 19:51
  • @Wichael please add your complete code including the used types to your question .. you say you use a `new int();` which looks pretty odd ... now here you say you actually use some `new Table()` and then try to access a certain member `tableItem` .. please add this class to your question .. – derHugo Jul 13 '20 at 19:51
  • @Charleh example added. – Wichael Jul 13 '20 at 20:10
  • @derHugo the int example was off the top of my head to try explain the problem. I've edited the original post with my actual code. – Wichael Jul 13 '20 at 20:11
0

The constructor parameter is the initial capacity of the internal array used by the list. The initial item Count is always 0. You can only access indexes in the range [0 .. Count - 1] (including Count - 1). The initial capacity does not change this.

You can only change the apparent size given by Count by adding or removing items with Add, AddRange, Clear, Insert, InsertRange and one of the 4 Remove variants.

A good initial capacity contributes in minimizing the number of required internal array resize operations but has no visible effect otherwise.

Therefore, if you have an index which might exceed Count - 1, you should get items with

if (i < list.Count) {
    int item = list[i];
    Process(item);
}

If you need a fixed collection size, use an array instead:

const int N = 20;
int[] arrayName = new int[N];

Now you can access all the indexes in the range [0 .. N - 1] (including N - 1).


If all this does not work, then maybe the list you are trying to access is not the same you initialized. If it is a class field, then maybe the it is in another object of the same class type. If it is a local variable (a variable declared inside a method), then it will only live during a single call of this method. (I'm not talking about enumerators and async/await here.)

See: List Class (Microsoft Docs)

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
  • I've increased the size by Add in my edited example above. Although the List I'm adding to is a list of class items, the class is correct. I don't think it;s a problem with the a local variable either... I've written a test code using the same code logic I've used here and it worked... But for some reason the above code won't... – Wichael Jul 13 '20 at 20:16
  • It seems that @derHugo found the origin of your problem with more context information. You got an `NullReferenceException` which has nothing to do with the size of the list, nor with indexing it. If an index was wrong you would get an `IndexOutOfRangeException`. – Olivier Jacot-Descombes Jul 14 '20 at 11:04
0

Your question actually has nothing to do with the list count or indices at all!

The actual issue: You never initialize the rawTableData list so it is null when trying to add elements to it in

tables[currentTable].rawTableData.Add(line);

You should simply declare it as

[System.Serializable]
public class DataItem
{
    public List<string> rawTableData = new List<string>();
}
derHugo
  • 83,094
  • 9
  • 75
  • 115
  • 1
    THANK YOU! I knew it had to be something like this but couldn't figure out what I was missing... So I now know that to be safe I should always = new List; any list I create... Thank you for saving my hair from being pulled out further. I will thank you every time I use shampoo and appreciate what I have on my head because of you. – Wichael Jul 13 '20 at 20:31
  • 1
    @Wichael the lesson to be learned here is to not make an assumption of what the issue is and instead post your error/call stack. I reckon you could have got an answer in about 60 seconds had you posted your error! – Charleh Jul 13 '20 at 21:40
  • @Wichael glad to help :) But yes I fully agree with Charleh. A [`NullReferenceException`](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) is one of the most basic errors to get in c# and OOP in general. You could have easily find the actual issue by [**debugging**](https://docs.unity3d.com/Manual/ManagedCodeDebugging.html) your code on runtime. And yes in general: Always initialize your collections as soon as possible, most of the time this is already together with the field declaration ;) – derHugo Jul 14 '20 at 06:06