C#의 List클래스

C#에서 지원하는 콜렉션으로 내부 자료형으로 클래스를 넣을 수 있어서 활용도가 매우 높다..!

또한, 정적 배열이 아닌 동적으로 배열의 크기를 조절할 수 있고 많은 기능을 포함하고 있다.

인덱스로 액세스할 수 있는 강력한 형식의 개체 목록을 나타냅니다. 목록의 검색, 정렬 및 조작에 사용할 수 있는 메서드를 제공합니다.

list 요소 삭제

using System.Collections.Generic;
using UnityEngine;

public class ListRemove : MonoBehaviour
{
    private List<int> myList = null;
    void Start()
    {
        myList = new List<int>();
        myList.Add(1);
        myList.Add(2);
        myList.Add(3);
        myList.Add(4);

        foreach (var param in myList)
        {
            print(param);
        }
    }
}

위 처럼 간단한 c# list코드가 있다고 한다면 코드는 문제없이 돌아간다.

1 2 3 4 출력

public class ListRemove : MonoBehaviour
{
    private List<int> myList = null;
    void Start()
    {
        myList = new List<int>();
        myList.Add(1);
        myList.Add(2);
        myList.Add(3);
        myList.Add(4);

        foreach (var param in myList)
        {
            print(param);
        }

        for (int i = 0; i < myList.Count; i++)
        {
            print(myList[i]);
            myList.RemoveAt(i);
        }

        foreach (var param in myList)
        {
            print(param);
        }
    }
}

이 코드도 일단 문제없이 돌아간다.

보기에는 문제가 없어보이지만 실제로 작동방식을 보면 큰 문제를 초래할 수 있다.

저 코드에서 출력값은

  • 첫 번째 foreach문은 1 2 3 4
  • 두 번째 for문은 1 3
  • 세 번째 for문은 2 4

버그아니야..? 라고 생각할 수 있지만 list의 특성과 코드를 자세히 다시 본다면 정상적인 코드이다.

처음 list.add당시 배열에는 1, 2, 3, 4가 들어간다.

두 번째 for문의 경우 반복 조건은 myList.Count이므로 총 4번의 반복을 해야한다. 증감은 +1씩 이루어진다.

list는 요소를 삭제하는 경우 인덱스를 앞으로 하나씩 밀기 때문에 빈 공간이 존재하지 않는다.

따라서 처음 1을 삭제하고 나머지 2, 3, 4의 인덱스가 하나씩 밀리고 list의 크기가 1 줄어든다.

{2, 3, 4} 크기 3 i는 1

다음 반복문에서 삭제되는 값은 3으로 배열의 크기만큼 순회하게 된다.

{2, 4} 크기는 2 i는 2

반복 종료..

실제로 list에 남아있는 값은 2, 4가 남아 있지만 반복은 정상적으로 종료된 상태이다.

이러한 list의 요소를 순회 삭제하고 싶다면 어떤 방식으로 접근해야 할까..?

역 순회

for (int i = myList.Count - 1; i >= 0; i--)
{
    print(myList[i]);
    myList.RemoveAt(i);
}

처음부터 배열의 마지막부터 삭제를 한다면 인덱스의 당김 없이 원할하게 삭제가 가능하다.

인덱스 0으로 순회

정리하다가 테스트해본 방법인데 위험성은 있지만 재밌는 것 같아서..?

for (int i = 0; i < myList.Count; )
{
    print(myList[i]);
    myList.RemoveAt(i);
}

위 방법도 정상적으로 삭제는 되지만 2가지 큰 문제점이 있다.

  1. 리스트의 크기가 매우 큰 경우 아마도 삭제할 때 마다 인덱스의 당김 작업이 있을 텐데 배열의 크기만큼 시간이 든다.
  2. 만약 삭제에 대한 조건이 있을 경우 증감이 없기 때문에 조건이 맞지 않는다면 무한루프에 빠지게 될 수 있다..!

정리하자면 list의 삭제의 경우에는 역반복을 사용하여 요소를 삭제해야 한다..!

댓글남기기