[C# 기초] 7. 컬렉션(Collection)


배열, 리스트, 해시테이블 등과 같이 비슷한 성격을 가진 데이터를 모아놓는 자료구조를 컬렉션이라고 합니다.

컬렉션(Collection)


컬렉션은, 같은 성격을 띠는 데이터의 모음을 담는 자료구조를 말합니다. 같은 성격의 데이터의 묶음들을 배열로 사용해보신적이 있으실 겁니다. C#은 컬렉션이라는 개념으로 배열뿐만 아니라, ArrayList, Queue, Stack, Hashtable 등 여러가지 컬렉션 클래스를 제공합니다.

예를 들어, Hashtable은 Key와 Value가 쌍으로 이루어진 데이터를 다룰때 사용합니다. 자료구조에서도 배우겠지만, 해싱으로 아주 빠른 탐색속도를 자랑합니다.

예제 코드:

using System.Collections;

class Program
{
    static void Main(string[] args)
    {
        Hashtable Ht = new Hashtable();
        Ht["하나"] = "One";
        Ht["둘"] = "Two";
        Ht["셋"] = "Three";
        
        Console.WriteLine("요소 직접 접근: {0}", Ht["셋"]);
            
        Console.WriteLine("==Hashtable의 모든 데이터 접근==");
        foreach(var value in Ht.Values)
        {
            Console.WriteLine(value);
        } // Two, One, Trre

        Console.WriteLine("==Hashtable의 모든 Key 접근==");
        foreach (var key in Ht.Keys)
        {
            Console.WriteLine(key);
        } // 둘, 하나, 셋
    }
}

인덱서(Indexer)


자료구조를 사용해보면 ‘arr[i]’와 같이 인덱스로 접근하는 방식이 편리합니다. 인덱서는 새로 생성한 클래스의 필드로 존재하는 컬렉션에 대해 클래스의 인덱스로 접근할 수도 있습니다.

사용방법:

class 클래스이름
{
	한정사 인덱서형식 this[형식 index]
    {
		get
		{
			// index를 이용하여 내부 데이터 반환
		}
		set
		{
		    // index를 이용하여 내부 데이터 저장
		}
	}
}

예제 코드:

using System.Collections;

class MyList
{
    private int[] array;

    public MyList()
    {
        this.array = new int[3];
    }

    public int this[int index]
    {
        get
        {
            return array[index];
        }
        set
        {
            if(index >= array.Length)
            {
                Array.Resize<int>(ref array, index + 1);
                Console.WriteLine("array resized : {0}", array.Length);
            }
            array[index] = value;
        }
    }

    public int Length
    {
        get
        {
            return array.Length;
        }
    }

}

class Program
{
    static void Main(string[] args)
    {
        MyList mylist = new MyList();

        Console.WriteLine("==데이터 저장==");
        for(int i=0; i<5; i++)
        {
            mylist[i] = i;
        } // array resize : 4 , 5

        Console.WriteLine("==데이터 출력==");
        for (int i = 0; i < mylist.Length; i++) // foreach를 사용할 수 없습니다.
        {
            Console.WriteLine(mylist[i]);
        }    // 0 , 1, 2, 3, 4
    }
}

위와 Mylist라는 객체에 대한 데이터를 인덱스로 접근할 수 있게 만들었습니다. 하지만 조금만 생각해보면 foreach문은 불가능하다는 사실을 아실겁니다. Mylist라는 객체만 보고 요소하나하나를 어떻게 판단할 것이며, 어떻게 순회할지에 대한 약속이 전혀 없기 때문입니다.

그렇다면 foreach문이 가능한 객체는 어떻게 만들 수 있을까요?

IEnumerable, IEnumrator: foreach문이 가능한 객체만들기


foreach문이 가능하기 위해서는 IEnumerable, IEnumerator를 상속받아 구현하면 됩니다. 즉, IEnumerable, IEnumerator 를 구현하면서 약속을 정해주어야하는 것입니다.

IEnumerable

메소드설명
IEnumerator GetEnumerator()IEnumerator 형식의 객체를 반환

IEnumerator

메소드설명
boolean MoveNext()다음 요소로 이동합니다. 컬렉션의 끝을 지난 경우에는 false, 이동이 성공한 경우에는true를 반환합니다.
void Reset()컬렉션의 첫 번째 위치의 ‘앞’으로 이동합니다. 첫번째 위치가 0번째라면 -1번으로 이동합니다. MoveNext()를 호출한 다음에 이루어집니다.
Object Current { get; }컬렉션의 현재 요소를 반환합니다.

예제 코드:

using System.Collections;

class MyList : IEnumerable , IEnumerator
{
    private int[] array;
    int position = -1;
    public MyList()
    {
        this.array = new int[3];
    }

    public int this[int index]
    {
        get
        {
            return array[index];
        }
        set
        {
            if(index >= array.Length)
            {
                Array.Resize<int>(ref array, index + 1); 
                Console.WriteLine("array resized : {0}", array.Length);
            }
            array[index] = value;
        }
    }

    public object Current
    {
        get
        {
            return array[position];
        }
    }

    public void Reset()
    {
        position = -1;
    }

    public bool MoveNext()
    {
        if( position == array.Length -1)
        {
            Reset();
            return false;
        }

        position++;
        return (position < array.Length);
    }
    public IEnumerator GetEnumerator()
    {
        for(int i=0; i <array.Length; i++)
        {
            yield return (array[i]);
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        MyList mylist = new MyList();

        Console.WriteLine("==데이터 저장==");
        for(int i=0; i<5; i++)
        {
            mylist[i] = i;
        }

        Console.WriteLine("==데이터 출력==");
        foreach(var item in mylist) // foreach가 가능해졌습니다.
        {
            Console.WriteLine(item);
        }    
    }
}

상황에 따라 배열과 리스트 같은 다양한 자료구조가 필요한데 이 컬렉션을 통해 많은 자료구조를 사용할 수 있을 뿐만 아니라 각각의 자료구조에 대해 변환도 쉽게 할 수 있습니다.