How to Remove Specific Variable in List

I have a somewhat overly convoluted class that makes a list of names, and allows you to spin through the names to pick one at random. The issue I’m running into is when I try to remove specific names from the list. I understand my script is probably incredibly sloppy and inefficient, but here it is,

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class TextWheelFlooper : MonoBehaviour
{
    public Vector3 offset;
    public List<MenuObjectMover> textPros;
    public List<string> texts;
    public List<GameObject> menuObjs;
    [SerializeField] bool isMenu;
    public Vector2 spinCount;
    public float spinDelay;
    string indexer;
    public TextMeshProUGUI nameObjectForEdit;
    public Transform spawnPointForNameEdit;
    public float yToAddToSpawnList;
    public GameObject nameDeletePanel;
    List<TextMeshProUGUI> listOfDeletePanelNames;
    bool deleteNamesAreInstantiated;
    public TextMeshProUGUI namesList;
    bool rouletteSpin;
    public int namesAmt = 0;
    [SerializeField] private int numberCount = 0;
    public TextMeshProUGUI menuObj;
    public float lengthMultiplier = 10, numberToAdd;
    private Vector3 posGoal;
    public GUIFunctionality gUI;
    bool init;
    void Start()
    {
        nameDeletePanel.SetActive(false);
        posGoal = transform.position;
        namesAmt = PlayerPrefs.GetInt("namez" +"A");
        if (Screen.width == 1920)
        {
            offset = new Vector3(950, offset.y, offset.z);
        }
        else
        {
            offset = new Vector3(1075, offset.y, offset.z);
        }
        if (namesAmt > 0)
        {
            PopulateList("A");
        }
        init = true;
    }
    public void PopulateList(string index)
    {
        indexer = index;
        namesList.text = " ";
        namesAmt = PlayerPrefs.GetInt("namez" + index);
        if(textPros.Count > 0)
        {
            for (int i = 0; i < textPros.Count; i++)
            {
                Destroy(textPros[i].gameObject);
            }
        }
        texts = new List<string>(namesAmt);
        textPros = new List<MenuObjectMover>();
        if (PlayerPrefs.GetString("names" + index + 1) != "")
        {
            for (int i = 0; i < namesAmt + 1; i++)
            {
                if (PlayerPrefs.GetString("names" +index + i) != "")
                {
                    texts.Add(PlayerPrefs.GetString("names" +index + i));
                }
            }
            if (texts.Count > 0)
            {
                for (int i = 0; i < texts.Count; i++)
                {
                    textPros.Add(Instantiate(menuObj.GetComponent<MenuObjectMover>(), transform.position, Quaternion.identity, transform));
                    menuObjs.Add(textPros[i].GetComponent<MenuObjectMover>().gameObject);
                    if (!isMenu)
                    {
                        textPros[i].GetComponent<TextMeshProUGUI>().text = texts[i];
                    }
                }
                textPros[numberCount].textSizeGoal = 1.5f;
            }
            UpdateWheel();
        }
    }
    private void Update()
    {
     
    }
    public void CloseDeletePanel()
    {
        nameDeletePanel.SetActive(false);
    }
    public void OpenNameDeletePanel()
    {
        if (deleteNamesAreInstantiated && listOfDeletePanelNames.Count > 0)
        {
            for (int i = 0; i < listOfDeletePanelNames.Count; i++)
            {
                Destroy(listOfDeletePanelNames[i].gameObject);
            }
        }
        nameDeletePanel.SetActive(true);
        if (texts.Count > 0)
        {
            listOfDeletePanelNames = new List<TextMeshProUGUI>(texts.Count);
            for (int i = 0; i < texts.Count; i++)
            {
                listOfDeletePanelNames.Add(Instantiate(nameObjectForEdit, spawnPointForNameEdit.position, Quaternion.identity, spawnPointForNameEdit));
                listOfDeletePanelNames[i].text = texts[i];
                listOfDeletePanelNames[i].transform.position = new Vector3(spawnPointForNameEdit.position.x, spawnPointForNameEdit.position.y - i * yToAddToSpawnList, spawnPointForNameEdit.position.z);
                listOfDeletePanelNames[i].GetComponent<NumberAssigner>().index = i;
            }
            deleteNamesAreInstantiated = true;
        }
    }
    public void RemoveName(int num)
    {if (texts[num] != null)
        {
            texts.Remove(texts[num]);
            namesAmt--;
            PlayerPrefs.SetInt("namez" + indexer, namesAmt);
            SaveNameList();
            PopulateList(indexer);
         
            OpenNameDeletePanel();
         
        }
    }
    public void NumberFlip(int num)
    {
        numberCount += num;
        UpdateWheel();
    }
    public void UpdateWheel()
    {
        for (int i = 0; i < textPros.Count; i++)
        {
            if(i == numberCount)
            {
                textPros[i].textSizeGoal = 1.5f;
            }
            else
            {
                textPros[i].textSizeGoal = 1f;
            }
                textPros[i].textPosGoal = new Vector3(((numberCount - i)) * numberToAdd + offset.x, transform.position.y, transform.position.z);
         
        }
        UpdateNameListText();
    }
    void SaveNameList()
    {
            for (int i = 0; i < namesAmt; i++)
            {
                if (PlayerPrefs.GetString("names" + indexer + i) != "")
                {
                PlayerPrefs.SetString("names" + indexer + i, texts[i]);
                }
            }
     
    }
    void UpdateNameListText()
    {
        namesList.text = " ";
        if (texts.Count > 0)
        {
            for (int i = 0; i < texts.Count; i++)
            {
                if (i != texts.Count - 1)
                {
                    namesList.text += texts[i] + ", ";
                }
                else
                {
                    namesList.text += texts[i] + "";
                }
                }
        }
    }
    public void AddRemoveList(string name, bool adding)
    {
        if (!rouletteSpin)
        {
            if (adding)
            {
                texts.Add(name);
                textPros.Add(Instantiate(menuObj.GetComponent<MenuObjectMover>(), transform.position, Quaternion.identity, transform));
                menuObjs.Add(textPros[textPros.Count - 1].GetComponent<MenuObjectMover>().gameObject);
                textPros[textPros.Count - 1].textPosGoal = new Vector3(((numberCount - (textPros.Count - 1))) * numberToAdd + offset.x, transform.position.y, transform.position.z);
                textPros[textPros.Count - 1].GetComponent<TextMeshProUGUI>().text = name;
            }
            else
            {
                texts.Remove(texts[texts.Count - 1]);
                Destroy(menuObjs[menuObjs.Count - 1].gameObject);
                Destroy(textPros[textPros.Count - 1]);
                 textPros.Remove(textPros[textPros.Count - 1]);
                menuObjs.Remove(menuObjs[menuObjs.Count - 1]);
            }
        }
        UpdateNameListText();
    }
    public void SpinRoulette()
    {
        if (namesAmt > 0)
        {
            StartCoroutine(RouletteSpin());
        }
    }
    IEnumerator RouletteSpin()
    {
        rouletteSpin = true;
        numberCount = 0;
        int spinners;
        spinners = (int)Random.Range(spinCount.x, spinCount.y);
        for (int i = 0; i < spinners; i++)
        {
            yield return new WaitForSeconds(spinDelay);
            if (numberCount < texts.Count - 1)
            {
                NumberFlip(1);
            }
            else
            {
                NumberFlip(-numberCount);
            }
        }
        rouletteSpin = false;
    }
 
}

So, what I’m trying to do is in the RemoveName method, I want to remove a name from the list, and basically save the list again to player prefs and repopulate the list. It basically deletes everything and then reinstantiates it. But, for some reason, occasionally the list will all be deleted with no errors on clicking a delete button. Also, more importantly, it seems to move one of the names to the top of the list? For example, here I have a list of names I just made, I will delete Jeff.


This is not what I was expecting, but this happened lol


I only deleted the one, yet for some reason the whole list seems to have cleared(i can see in the inspector). It is supposed to be repopulated through player prefs(which looking at it now, the amount of names is still saved to 5 and the names are all there!)

Sorry for the convoluted question, I didn’t even realize as I was writing this there was so much going wrong with my script. Would someone be able to help me figure this out, please?

Thanks in advance

Edit: I just found in my testing that the “indexer” variable gets cleared at some point, which is causing at least one of the problems… I can’t find where though…

First of all, it looks like you should really be using RemoveAt() instead of Remove(). RemoveAt() removes the item at a specific position in the List, and is more efficient. Remove() searches the list for something equal to the object you asked it to remove, which is more expensive, and isn’t guaranteed to remove the index that you expect if your list contains duplicates. Every place I see that you’re calling Remove, it looks like you already know the exact index that you want to remove, so there’s no reason not to use RemoveAt() instead.

Second, I don’t know why you’re trying to save the list to playerprefs and then regenerate it every time. That’s pretty inefficient, and it’s not what playerprefs is designed to be used for, and I wouldn’t be surprised if that code contains several bugs. You’ve got a bunch of string literals and string expressions that need to exactly match across several different places in your code or else things will stop working (you could make this less dangerous if you used constants for the strings and helper functions for the expressions). I also notice that the save function doesn’t save the size of the list, you are relying on the function that calls SaveNameList to also save the size; that’s downright reckless.

On line 68, why are you adding 1 to the loop max when loading the list? It doesn’t look like you do that when saving it.

It also looks like if the saved list has exactly 1 element, the load function just…ignores it? (The “if” on line 66 looks for index #1, but the first entry would be index #0, and it’s not clear why that “if” is needed at all.)

None of that seems particularly likely to explain your current symptom, though.

1 Like

Hmm, It seems to work a bit better now? It’s deleting the specific names from the list, although it doesn’t properly delete the object, I’ll have to rework that.

I know it’s inefficient, but the reason I did it was because I want it to move every number after it up one. So say it’s ,“John, James, Jack” And it’s saved under namesA, it will be namesA1, namesA2, and namesA3. But if you delete, say, James, I want Jack to now be saved under namesA2 instead of A3. I’m sure there’s an easier way to do this haha, I suppose I could only save the ones after the one that was delete by using a for loop and int i = num (the one that was deleted). I could also open a filestream, the reason I thought I would just do it in playerprefs is because it was originally only going to be one list, then my partner informed me we would need multiple lists after I finished coding everything :confused: lol. I’m not super skilled at serialization, but if I ever implement this in a game I’ll keep that in mind. This is one tool of a few in my app, all it is is a name roulette, so it can stand to be a little inefficient for now :stuck_out_tongue:

Ah, and I have no idea why I was adding 1 haha, I fixed it after posting this lol. I think I used to have it add the “namesAmt” to that and that’s why it’s adding one instead of 0.

I might have fixed it just now… as I was typing this lol. The indexer was being declared in the inspector, but for some reason it wasn’t always registering, I turned it private and set it in the script. I’ll send it to my partner and have him test it out, hopefully it works…

Thanks for the help

Maybe I misunderstood what you are trying to do but wouldn’t it be something like this?

using System.Collections.Generic;
using UnityEngine;

public class ListTest : MonoBehaviour
{
    List<string> myList = new List<string>();

    private void Start()
    {
        myList.Add("A");
        myList.Add("B");
        myList.Add("C");
        myList.Add("D");
        myList.Add("E");
        myList.Add("F");

        int count = myList.Count;

        for (int i = 0; i < count; i++)
        {
            Debug.Log("[" + i + "]" + myList[i]);
        }

        myList.RemoveAt(4);

        count = myList.Count;

        for (int i = 0; i < count; i++)
        {
            Debug.Log("[" + i + "]" + myList[i]);
        }
    }
}

6547381--740707--556.png