본문 바로가기

.NET/C#

C# Collection

728x90
반응형

몇일 쉬었다가 다시 글을 쓸려니 왠지 적응도 안되고 아침 내내 추위에 덜덜 떨어서 머리상태도 병맛(?)이고 -_-;;;안좋은 상태에서 글을 남기게 되내요 ㅎㄷㄷ

이번에는 Collection이란 넘을 알아보려고 합니다.
System.Collections 여기에 담겨져 있는 수많은 collections 클래스를 쓸수가 있죠.

최근 경향은 제네릭형을 많이 쓰자는 경향이라서 Collections 보다는 Collections.Generic의 클래스들을 더 많이 사용하고는 있는데요. 둘의 차이라고 한다면 유연한 타입 변경이라고 할 수가 있겠지요. 제네릭에 대해서는 다음기회에 알아보도록 하고요 ^^(솔직히 아는게 별로 없어서 ㅜㅜ 죄송합니다 (_ _)

Collection도 배운게 별로 없는지라 깊게는 못들어갈 꺼 같네요. 우선 수박 겉 핥기 식으로 넘어가긴 하겠지만 그래도 뭐 이정도의 Collection 지식이라면 어느정도 도움은 되지 않을까 생각이 들긴합니다.

그럼 본론으로 들어가보겠습니다.

Collections에 들어가 있는 여러가지 클래스들이 있지만 이번에는 몇가지만 알아보도록 하겠습니다.
우선 첫번째로 ArrayList에 대해서 알아보도록 하지요.

ArrayList는 고급 버전의 배열이라고 할 수 있죠. Array클래스에서는 제공되지 않는 일부 기능을 제공합니다.
1. Arraylist의 용량은 필요에 따라서 자동으로 확장됩니다. Capacity속성의 값이 변경될 경우 메모리 재할당 및 요소 복사가 자동으로 이루어 지죠
2. 요소 범위를 추가, 삽입 또는 제거하는 메소드들을 제공하고 있습니다~
3. 읽기 전용 및 고정 크기의 래퍼를 컬렉션에 반환하는 메소드를 제공하지요
4. 하한이 항상 0이라는 단점.
5. 차원이 항상 일차원만 가질수 있습니다.
6. 특정 형식의 성능은 Array보다 많이 떨어진다는 단점이 있습니다.
읽기 전용이나 고정 크기의 래퍼를 만들대나 용량이 변할 수 있는 배열이 필요할 때 추가 삽입 제거가 되어야 할 상황이라면 ArrayList를 사용하면 좋겠지요

사용방법을 알아보도록 하지요 우선 Add 메소드를 사용해보겠습니다.

    1 class Program

    2 {

    3     static void Main(string[] args)

    4     {

    5         ArrayList al = new ArrayList();

    6         al.Add(1);

    7         al.Add("Hello");

    8         al.Add(DateTime.Now);

    9         al.Add(11.12);

   10         for (int i = 0; i < al.Count; i++)

   11             Console.WriteLine(al[i]);

   12     }

   13 }
ArrayList 객체를 생성하고 거기에 Add메소드로 값들을 추가하는 모습인데요 결과를 확인해 보시면 다음과 같습니다.

형이 다른 데이터들이 한 객체 안에 들어가서 제대로 출력되는 모습을 볼수가 있죠
그럼 저 객체에 데이터를 삽입, 제거하는 것을 보도록 하지요. 의외로 참 쉽죠. 메소드 하나씩만 날려주면 해결이 됩니다.

    1 class Program

    2 {

    3     static void Main(string[] args)

    4     {

    5         ArrayList al = new ArrayList();

    6         al.Add(1);

    7         al.Add("Hello");

    8         al.Add(DateTime.Now);

    9         al.Add(11.12);

   10         al.Insert(1, "Insert Data");

   11         al.Remove(al[4]);

   12         al.RemoveAt(3);

   13         for (int i = 0; i < al.Count; i++)

   14             Console.WriteLine(al[i]);

   15     }

   16 }

다음과 같이 수정하고 실행을 시키면 다음과 같이 출력이 되죠.

배열 1자리에 Insert Data가 추가된것을 볼수 있고요
4자리의 11.12가 지워지고 또 3자리의 DateTime.Now의 결과가 사라진것을 확인할 수 있죠
마지막 한가지 더....
어디에나 있는 IndexOf 이지요 여기서도 마찮가지로 해당 데이터가 어디에 위치해 있는지 위치값을 반환해주는 아주 고마운 메소드입니다. 이녀석 잘 활용하면 재미있는 짓(?)을 쫌 할 수 있을지도 모르죠~ㅎㅎㅎ
다음은 Stack에 대해서 살펴보죠. 이녀석은 많이 들어보셨을 겁니다. 자료구조 같은곳에서 정말 시도 때도 없이 나오는 녀석이지요. 스택하면 선입후출을 생각하게 되죠. 아래의 테스트 코드를 실행을 하시면 stack의 특징을 바로 확인할 수 있습니다.

    1 class Program

    2 {

    3     static void Main(string[] args)

    4     {

    5         Stack stackTest = new Stack();

    6         stackTest.Push(1);

    7         stackTest.Push("Hello");

    8         stackTest.Push(DateTime.Now);

    9        int count = queueTest.Count;

   10         for (int i = 0; i < stackTest.Count; i++)

   11         {

   12             Console.WriteLine(stackTest.Pop());

   13         }

   14         Console.WriteLine(stackTest.Count);

   15     }

   16 }


실행 화면을 보시면 입력은 1부터 하였지만 1이 제일 마지막에 출력되는것을 볼수가 있지요. 그것은 바로 Stack의 선입후출의 특징때문에 일어나는 일이라는 것을 볼수가 있습니다. Stack의 또다른 읽기 방법중 하는 Peek()인데요 이녀석은 pop과는 좀 다른 기능을 보여줍니다 pop 대신 peek를 입력하고 실행을 해보십시요.

다음과 같이 나오는데요 그 이유는 pop은 읽으면서 데이터를 삭제하지만 peer는 읽기만 하고 데이터의 삭제가 일어나지 않기 때문에 한곳의 데이터만 읽게 되는 것입니다. 그래서 위와 같은 결과가 나오게 되는 것이지요.
그럼 Stack은 여기서 마물하겠습니다. 근데 Stack을 해봤는데 이녀석을 안해보면 상당히 섭섭해 하겠죠?? 네 바로 Queue입니다. 이녀석 또한 간단하게만 알아보죠. 이녀석은 선입후출의 반대인 선입선출을 기능으로 하는 녀석입니다. 항상 먼저 들어온게 먼저 나가죠. 그래서 이름도 큐이고요 -_-;;(추운데 썰렁개그 죄송 (_ _))
요넘에게도 입력과 제거, 일기 기능이 있습니다. 다른 기능들은 MSDN에서 봐주시길 헐....
Queue의 테스트를 한번 진행해 보도록 하지요~

    1 class Program

    2 {

    3     static void Main(string[] args)

    4     {

    5         Queue queueTest = new Queue();

    6         queueTest.Enqueue(1);

    7         queueTest.Enqueue("Hello");

    8         queueTest.Enqueue(DateTime.Now);

    9 

   10         int count = queueTest.Count;

   11         for (int i = 0; i < count; i++)

   12         {

   13             Console.WriteLine(queueTest.Dequeue());

   14         }

   15         Console.WriteLine(queueTest.Count);

   16 

   17     }

   18 }

다음과 같이 해났는데요. Dequeue()는 Stack의 Pop과 같은 기능입니다. 단지 앞의 데이터를 먼저 읽고 제거한다는게 틀린거죠. 실행 결과를 봐볼까요?

보시는것과 같이 입력하였던 순서대로 출력되는것을 볼수 있지요. 그럼 Dequeue를 Peek로 바꾸어서 실행해 보세요. 그러면 역시 메모리에서 지워지지 않기 때문에 Stack과 비슷한 결과를 보실수 있을 겁니다. 단 다른점은 Stack은 제일 마지막 데이터를 출력하지만 Queue는 제일 첫 데이터를 출력한다는 거지요~.

이 다음 알아볼 것은 HashTable입니다~ HashTable은 key와 value를 쌍으로 저장하는 구조입니다. 자료를 찾을 때 key로 접근을 한다는 것때문에 검색이 제일 빠르다는 장점을 가지고 있지만 key와 value를 가지고 있다는 점에서 저장공간이 커진다는 단점이 있죠~ ^^
뭐 모든 것들이 장점과 단점을 다 가지고 있지만 말입니다~ ㅎㅎ

해쉬테이블에 대해서는 그저 간단히 알아 보고 넘어가겠습니다~(두시간동안 이걸 보고 있었더니 슬슬 이해력이 떨어지고 있다는 ㅜㅜ)
 

    1 class Program

    2 {

    3     static void Main(string[] args)

    4     {

    5         Hashtable ht = new Hashtable();

    6         ht.Add('1', "첫번째 데이터");

    7         ht.Add('2', "두번째 데이터");

    8         ht.Add('3', "세번째 데이터");

    9         ht.Add('4', "네번째 데이터");

   10 

   11         for (int i = 0; i < ht.Count; i++)

   12         {

   13             Console.WriteLine(ht[char.Parse((i + 1).ToString())]);

   14         }

   15     }

   16 }

음...HashTable의 예로는 솔직히 맞지는 않습니다만...이해를 돕고자 이런 예문을 써보았습니다.
보시는봐와 같이 HashTable은 키값을 가지고 데이터를 찾습니다. 그래서 그 키값에 쉽게 접근할 수 있어 검색 속도가 빠르게 되는것이지요. 결과는 뻔한 값이 나오지만 확인해야겠지요 ^^


이제 마지막으로 반복문에서 제외하고 넘어왔던 foreach에 대해서 알아보려고 합니다.
foreach문은 배열이나 개체 컬렉션에 있는 각 요소에 대해 포함 문 그룹을 반복하여 실행하는 메소드입니다. foreach문을 사용하면 컬렉션을 반복 실행하여 원하는 정보를 얻을수 있지요. 단, 컬렉션의 내용을 변경할때는 비추라고 할 수 있습니다. 자신의 의도하지 않은 결과가 발생을 하기 때문이죠. 결국 읽기 전용이라는 말입니다!!!

원래 위에서 ArrayList의 값을 출력할 때 for문을 이용하여 다음과 같이 데이터를 출력했었죠

    1 static void Main(string[] args)

    2 {

    3     ArrayList al = new ArrayList();

    4     al.Add(1);

    5     al.Add("Hello");

    6     al.Add(DateTime.Now);

    7     al.Add(11.12);

    8 

    9     for (int i = 0; i < al.Count; i++)

   10     {

   11         Console.WriteLine(al[i]);

   12     }

   13 }

이것을 foreach문으로 바꾸는 과정을 보여 드리도록하겠습니다. 우선 이 과정에는 IEnumerator와 GetEnumerator()의 만남이 생겨서 foreach문을 탄생기키는데요 저 두개를 이용한 구현을 먼저 보여드리겠습니다.
우선 IEnumerator는 제네릭이 아닌 컬렉션에서 단순하게 반복할 수 있도록 지원하는 열거자를 노출하는 인터페이스입니다. GetEnumerator()는 컬렉션을 단순히 반복하는 열거자를 반환해주는 역할을 하고요. 두개의 만남으로 인하여 해당 컬렉션의 반복이 일어나게 되는 것이죠 구현을 해보도록 하죠

    1 static void Main(string[] args)

    2 {

    3     ArrayList al = new ArrayList();

    4     al.Add(1);

    5     al.Add("Hello");

    6     al.Add(DateTime.Now);

    7     al.Add(11.12);

    8 

    9     IEnumerator e = al.GetEnumerator();

   10     while (e.MoveNext())

   11         Console.WriteLine(e.Current);

   12     e.Reset();

   13 }

다음과 같이 구현해보았습니다. IEnumerator와 GetEnumerator는 MSDN의 도움을 받으시기를 바랍니다. 저도 짧은 지식으로 인해 100% 이해가 가지 않는 부분이라 ㅜㅜ
우선 e라는 al의 객체를 만들었습니다. while에서는 e의 컬렉션의 다음 위치의 정보의 유무로 반복시키고 e.Current로 해당 데이터를 출력하게 했습니다. 마지막에 다시 초기화 시켰고요. 이럼으로써 for문과 똑같은 기능을 하게 된 거죠.
근데 이 이해 안되는 코드를 맨날 쓸려면...헐...정말 미쳐버릴지도 모르겠죠. 그래서 foreach문이 있는거죠 저기능을 똑같이 구현해서 만든게 foreach문입니다. 저 구문 자체가 foreach문 자체인 거죠(100%믿지는 마세요...그렇게만 알고 있어서 아닐지도 ㅜㅜ) foreach문으로 구현을 해보도록 하겠습니다.

    1 static void Main(string[] args)

    2 {

    3     ArrayList al = new ArrayList();

    4     al.Add(1);

    5     al.Add("Hello");

    6     al.Add(DateTime.Now);

    7     al.Add(11.12);

    8 

    9     foreach (object obj in al)

   10         Console.WriteLine(obj);

   11 }


foreach문의 형식은 위에서 보는것과같이 foreach(변수 in 컬렉션) 이런 형식을 하고 있습니다.
컬렉션의 수를 직접 확인해서 출력해주기 때문에 따로 count 할 필요도 없고 쉽게 접근할 수 있기 때문에 참 강력한 반복문이라고 할 수 있죠. 위에서 IEnumerator가 어쩌구 저쩌구...저건 기억속에서 지우셔도 됩니다. foreach가 어떻게 작동한다는 건가를 알기 위해서 구현해본것이기 때문이죠. foreach문에 대해서 이해가 가셨는지 모르겠네요...혹시 모르시겠다면...덧글 남겨주세요 ㅎㄷㄷ 이해 시켜드리도록 노력하겠습니다 ㅜㅜ
아니면 MSDN이나 구글님에게 물어보셔도 방대한 자료를 찾으실수 있을꺼고요 -_-;;;

빈약한 자료와 지식으로 이렇게 글을 쓰다보니 많이 부족했는데요. 너그러이 용서해주시길 바랍니다. ㅜㅜ

진짜 더 많은 공부를 필요한다는거 느꼈고요 앞으로 더욱 공부해서 더 쉽고 편안하게 느낄 수 있도록 노력하겠습니다.

감사합니다~^^

728x90
반응형

'.NET > C#' 카테고리의 다른 글

Windows Forms의 시작  (2) 2010.01.19
C# Event  (0) 2010.01.18
C# delegate  (0) 2010.01.14
FileAndDirectory  (0) 2010.01.12
C# File Input/Output  (1) 2009.12.24
Interface  (0) 2009.12.18
Class(5)  (0) 2009.12.18
형변환에 대해서...  (0) 2009.12.18
System.Object 클래스 상속  (3) 2009.12.18
Property의 get, set 에 대한 간단한 정리  (0) 2009.12.18