반응형

출처: https://penguinofdev.tistory.com/51

특정 조건에 맞는 LIst 안의 원소를 제거할 때, 별 생각없이 이렇게 할 때가 있다.

for(int i = 0; i < myList.Count; i++)
{
	if(조건이 참일 때)
		myList.Remove(myList[i]);
}

배열이 됐든 무엇이든 순회하는 과정에서 컨테이너의 내용이 변경되는 것은 위험한 작업일 수 있다.

 

위 코드도 중간에 어떤 값이 제거되면, list의 사이즈 역시 변경되어 잘못된 인덱스에 접근할 가능성이 매우 높다.

 

이럴 때는 다음과 같이 사용하자.

for(int i = myList.Count - 1; i >= 0; i--)
{
	if(조건이 참이면)
    		myList.Remove(myList[i]);
}

거꾸로 순회하면서 제거하면 안전하게 작업을 수행할 수 있다.

 

 

 

- Question

InvalidOperationException: The list was modified.

InvalidOperationException: The list was modified. Boo.Lang.List`1+c__Iterator6[UnityEngine.GameObject].MoveNext () Item.OnCollisionExit (UnityEngine.Collision collision) (at Assets/Item.js:73)

I simply want a list with item I currently collide with, so when I stop colliding they must be removed from the list:

EDIT: I changed my code but now it gives an index out of range exception

  1. function OnCollisionExit(collision : Collision) {
  2. for(var i = tegenstanders.Count; i> 0; i--)
  3. {
  4. item = tegenstanders[i];
  5. if(item.name == collision.gameObject.name)
  6. {
  7. tegenstanders.Remove(tegenstanders[i]);
  8. }
  9. }
  10. }

- Answer


This happens because you're removing items from the list at the same time as you are iterating through it. It's easier to explain if you convert the list to a non-enumerated for-loop instead:

  1. List<int> example = new List<int>();
  2. for (int i = 0; i < example.Count; i++)
  3. {
  4. if (something)
  5. example.Remove(example[i]); // Not safe to do
  6.  
  7. }

If you remove an item from the list while you're going through it, the for-loop's impression of the list's Count-property is no longer reliable, since the amount of elements in the list changed during execution of the loop. In addition, the enumeration is now messed up; example[i] now points to another item in the list, because the Remove-command has shifted all of the elements with a higher index down to keep them sequential in memory, so you would effectively skip an item if you kept iterating with it. That's why the enumerated version of the loop doesn't enjoy it very much when you modify the List in it.

To get around this issue, use a standard for-loop and iterate through the list backwards instead:

  1. List<int> example = new List<int>();
  2. for (int i = example.Count-1; i >= 0; i--)
  3. {
  4. if (something)
  5. example.Remove(example[i]); // Safe to do
  6. }

This is not a problem, because you're stopping iteration at 0, not at List.Count, and all of your indexes still point to the right elements just fine, because the elements get shifted down on Remove, and you've already iterated through those.

반응형

+ Recent posts