- Home /
List That Won't Remove The Last Two Elements
Alright, so I'm setting up a little subtitle GUI for a project, and I'm doing this by building a list of strings (the words), then feeding them to a Text GUI in 16 word segments.
Relevant Code:
int wordsDisplayed = 16;
//All of the following is inside an IEnumerator named 'Delay'
if (list.Count > 0)
{
Debug.Log (list.Count);
text.GetComponent<Text> ().text = "";
if(list.Count >= wordsDisplayed)
{
for(int i = 0; i < wordsDisplayed; i++)
{
if(list[i]!=null)
{
text.GetComponent<Text> ().text += list[i];
list[i] = null;
}
}
}
else
{
for(int i = 0; i < list.Count - 1; i++)
{
if(list[i]!=null)
{
text.GetComponent<Text> ().text += list[i];
list[i] = null;
}
}
}
for(int i = list.Count - 1; i > 0; i--)
{
if(list[i]==null)
{
list.RemoveAt (i);
}
}
StartCoroutine(Delay (time, list));
}
//If list is empty, aka all words have been displayed, end the dialogue state
else
{
//End dialogue
}
The problem is that the Debug.Log() on line 5 is saying that the count of list is, starting from the first loop: 100, 84, 68, 52, 36, 20, 4, 2, 2, 2, etc... I can't figure out why is won't go ahead an remove the last two elements from the list. They're displayed just fine on the actual Text GUI component, they just won't remove themselves from the list. Any ideas on what's going on? Thanks in advance.
Answer by Gizmoi · Feb 03, 2015 at 08:13 AM
In the 2nd loop, your loop condition is i < list.Count - 1
meaning it will never check the last element and set it to null. In the final loop your condition is i > 0
meaning it will never check the first element in the array.
I'm assuming the first and last elements are the 2 remaining in your list.
Change the 2nd loop's condition to i < list.Count
and change the final loop's condition to i >= 0
Edit: It's also probably better to simply do
list.RemoveAt(i);
i--;
when you want to remove an item from your list rather than setting it to null then checking it later.
well, that's weird. It looks like I was assu$$anonymous$$g that the for loop would keep running one more time after its condition was considered false. I don't know what I was thinking. Thanks for the answer. oh yeah, and there was a reason why I am not using removeat(). I can't remember why right now.
Answer by daneislazy · Feb 03, 2015 at 10:19 AM
So, I realize that your issue has already been resolved, but I wanted to jump in to clear up a few things. First off for those still wondering, you are replacing the list with nulls because you are iterating over it with 'i' and if you remove the item the script will start skipping items. Instead of iterating over it you could just use text.GetComponent().text += list[0]; list.RemoveAt(0);
then check to see if the list is empty and break out of the for loop. Also you could use a while or modify your for to accomplish the break as well.
Also of note is that you seem to be using coroutines... oddly. If all that code is in the Delay IEnumerator then you are Recursively calling Delay from within itself. You really don't need to do that. If you use a while loop and a yield return new waitforseconds(time);
right before the end of the loop it will return and keep running after the set time without having to call it again.
It's probably best explained with actual code so here you go.
int wordsToDisplay = 16;
float textDelay = 10f;
List<string> list = new List<string>();
// or you can pass some/all into the IEnumerator, it will retain info between yields
IEnumerator Delay() {
// you could also grab the text component here so you are not doing it repeatedly
while(list.Count > 0) {
text.GetComponent<Text>().text = "";
for(int i = 0;(list.Count > 0 && i < wordsToDisplay);i++) {
text.GetComponent<Text>().text += list[0];
list.RemoveAt(0);
}
yield return new WaitForSeconds(textDelay);
// returns here after textDelay then rechecks the while loop
}
}
then you just have to set the list with the text and call StartCoroutine(delay());
Hope that helps clear things up, and I hope the code works (I didn't test it) or at least gets the idea across.
Wow. You just completely solved that annoying RemoveAt(i) problem. Damn, I looked on all sorts of boards (including this one) and the general consensus was to use a separate for loop to remove elements. Never thought to just pull out the first element every time. I try not to use while loops in Unity, because any time I screw up a single thing with the returns or conditions, then Unity will crash the second I test it. It just winds up being too much hassle. I really wish I could give you more up votes, that was very informative.
In this instance a while loop is much more readable for what you're trying to achieve, however the general consensus for removing elements in a list you are iterating over is RemoveAt(I) and then decrement i :)
Answer by NoseKills · Feb 03, 2015 at 08:16 AM
Few suspect thing in your code
for(int i = 0; i < list.Count - 1; i++)
{
if(list[i]!=null)
{
text.GetComponent<Text> ().text += list[i];
list[i] = null;
}
}
why aren't you adding and nulling the last item in the list. Looks like it might get left on the list. Should it be ?
for(int i = 0; i < list.Count; i++)
And Here
for(int i = list.Count - 1; i > 0; i--)
{
if(list[i]==null)
{
list.RemoveAt (i);
}
}
Same thing there. You don't do anything to the "0" index. You spot at index 1. Should it be ?
for(int i = list.Count - 1; i >= 0; i--)
thanks for taking the time to answer. I just chose the quickest answer.
Your answer
Follow this Question
Related Questions
A node in a childnode? 1 Answer
Multiple Cars not working 1 Answer
Affect every object in array. 1 Answer
Distribute terrain in zones 3 Answers
Removing a class object from a list(.remove not working) C# 1 Answer