본문 바로가기
[ Program ]/c#스터디

41.arraylist / List / StringBuilder / 참조추가법

by 관이119 2021. 10. 9.

이제까지 배운내에서 배열은 꼭 필요하지만 상당히 불편한 존재였다.

아니 다른걸 배우지 않으면 불편하다고 느끼지 못했을지도 모르겠다.

기존의 배열은 항상 길이를 정해두거나 초기화 할때 값을 넣어줘야했다.

그런데 만약 값이 몇개가 들어갈지 모르는 상황이 온다면 어떻게 해야할까?

당연히 프로그램을 하다보면 그런상황이 수도없이 발생한다.

예를 들면 소수(1과 자신만을 약수로 가지는수) 의 개수를 1000이내에서 구하는 배열을 만들려면 길이를 몇개로 해야할까?

외우고 있는 사람아니면 보통사람은 알수 없다.

그래서 동적으로 할당할수 있는 배열이 있다. 

다음예제를 보자.

 

ArrayList myAL = new ArrayList();
myAL.Add("Hello");
myAL.Add(1);
myAL.Add(false);

 

ArrayList 라는 클래스인데 위와 같이 선언만 해주고 add 로 원소를 추가해주면 배열이 자동으로 늘어나면서 계속 데이터를 넣을수 있게 된다.

이 ArrayList 는 내부적으로 데이터가 꽉차면 메모리용량을 늘리고 또 꽉차면 늘리고 하는 작업을 반복적으로 실행하는데 이 늘어나는 비율을 Growth factor(성장인자) 라고 한다.

보통은 늘리는 비율이 1.5~2배정도 되는데 자세한 내용은 아래 경로를 참고하자.

https://en.wikipedia.org/wiki/Dynamic_array

 

Dynamic array - Wikipedia

Several values are inserted at the end of a dynamic array using geometric expansion. Grey cells indicate space reserved for expansion. Most insertions are fast (constant time), while some are slow due to the need for reallocation (Θ(n) time, labelled with

en.wikipedia.org

 

그런데 저렇게 늘리는 작업을 하면 기존에 사용하던 일반배열보다 pc가 여러가지 일을 해야하니 프로그램이 느려지지 않을까 생각할수 있다.

당연히 느려진다.

해야할일이 많아 지니 아무것도 안하는것보다 느려지는게 당연하지만 그렇다고 알수없는 큰 공간을 잡아두고 안쓰고 계속 메모리 낭비를 하는것과 비교하면 서로 장단이 있는셈이다.

 

일단 위에서 말한 ArrayList 를 더 자세히 보자.

위예제에서 보면 Add 함수를 사용해 인자를 추가했는데 string 도 있고 int 도 있고 bool 값도 있다.

ArrayList 는 내부적으로 object 으로 박싱해서 데이터를 가지고 있기 때문인데 안그래도 기존배열보다 느린데 데이터를 넣을때마다 형변환까지 해야하니 더 cpu가 해야할일이 많아진다.

그렇다고 사용자가 어떤값을 넣을지 사실 미리 알수도 없으니 이렇게 저렇게 생각해봐도 답답하기만 하다.

 

그래서 또 ms에서 연구해서 제네릭타입이라는 것을 만들어냈다.

쉽게말하면 일반배열과 똑같은데 동적배열인것이다.

다음예제를 보자.

 

List<int> ar = new List<int>();

ar.Add(10);

 

arraylist 와 비슷하다.

제네릭은 나중에 다시 살펴보겠지만 일단은

List<타입> 배열명 = new List<타입>();

형식이라고 외워두자.

저 타입에는 이전에 배열에서 만들던것처럼 int 나 string 이나 아니면 클래스명등 어떤것이 들어와도 된다.

결국 그타입을 가지는 배열을 만들건데 동적배열로 만들거다 이런의미인것이다.

저렇게 사용하면 이전에 ArrayList 에서 발생하던 형변환(박싱) 은 발생하지 않는다.

처리시간이 줄어든다는 이야기이다.

 

우리가 사실 배열을 사용하면서 엄청난길이의 배열을 사용해야하는 경우는 별로없다.

좌표같은걸 저장할때 길어야 몇백개짜리배열을 사용하고 일반적으로는 100개미만이 대부분이다.

그래서 테스트 코드를 만들었다.

 

그림1

 

 

그림1을 보면 속도를 테스트할수 있는데 엄청난 길이의 배열을 테스트해도 속도차이는 거의없다.

단 arrayList 는 박싱으로 인해 속도가 좀 차이가 나긴한다.

결론적으로 보면 배열을 사용할때 제네릭 List 를 사용하는게 제일 낫다.

속도도 좋고 동적배열이니 사용하기도 편하다.

 

ArrayList 를 사용하고 싶다면 아래와 같이 사용하면 동일한 효과를 볼수 있다.

List<object> ar = new List<object>();

위와 같이사용하면 뭐든지 넣을수있는 동적배열이 되니 결국 ArrayList 와 같은것이다.

그런데 같은행동을 해도 실제로 테스트해보면 List 쪽이 훨씬빠르다.

심지어 형을 직접지정해준것보다 더빠를때도 있다.(?)

이유는 나도 정확히 알수 없다.

그만큼 내부적으로 효율화가 잘되어있다는 의미가 될것이다.

( ArrayList 는 동적배열 구색맞추기로 끼워넣은 실패작이고 List 가 심도있게 연구해서 만든게 아닌가 개인적으로 생각한다.)

 

 

배열에서 위와같이 확인해봤는데 우리가 사용하는 문자열도 가만히 생각을 해보자.

string str = "testtext";

위예제를 가만히 보면 결국 string 이라는것도 char 의 배열이다.

그러면 string 은 위 List 처럼 빠르게 만든게 없을까? 있다.

StringBuilder 라는 것인데 이것도 new 로 객체로 정의해서 사용하면 된다.

프로그램을 하다보면 문자열을 더해야하는경우가 많은데 내가 앞장에서는 StringBuilder 를 설명하지않았다.

갑자기 new 로 객체를 만들어야되면 너무 이해가 안될거같애서 건너뛴 내용인데 StringBuilder 는 문자에 한해서 List 처럼 스페셜 리스트로 생각하면 되겠다.

 

StringBuilder sb = new StringBuilder();
sb.Append(10);
sb.Append(false);
sb.Append("testText");
MessageBox.Show(sb.ToString());

 

위는 간단한 사용예제다.

속도 테스트를 해보면 string 과 StringBuilder 로 문자열을 합칠때 당연히 짧은 몇개는 거의 차이가 나지않는데 숫자가 늘어날수록 기하급수적으로 차이가 벌어진다.

 

오늘 이야기한 두가지는 상당히 중요한것들인데 잘이해가 가지않으면 그냥 쓰라니까 쓴다는 생각으로 사용하면 된다.

두가지 클래스의 함수들도 여러 복잡한 내용을 간단히 실행할수 있게 해주는 것들이 많으니 한번씩 살펴보자.

 

그림2

 

소스에서 그림2와 같이 입력하면 빨간줄이 생기고 아무것도 작동하지않는다.

앞에서 설명했는지 정확하게 기억이 나지 않는데 이런경우 해당 dll 을 참조하지 않아서 그런경우다.

위와같은경우 해당 위치에 마우스를 대면 그림3과 같이 바뀐다.

 

그림3

 

그렇게 바뀌면 그림3에 빨간부분바로위에 화살표를 눌러보자.

그림4

 

그러면 그림4와같이 선택할수 있는것들이 나올것이다.

대체로 그중 첫번째거를 선택하면 되는데 using 이 붙어있는 첫번째걸 선택하자.

그림5

 

그러면 그림5처럼 제일위쪽 상단부분에는 위쪽에 있는 코드가 생성되고 까만색이었던 코드는 클래스를 의미하는 초록색으로 변경될것이다.

그러면 이제 사용할수 있는 상태가 되었다는 의미인데 그렇게 사용하면 된다.

 

 

위방법이 마음에 들지 않으면 아래 그림6처럼 MSDN 을 찾아간다.

그림6

 

그러면 위쪽에 네임스페이스와 어셈블리가 나와있다.

그러면 가장상위에 using 으로 해당네임스페이스가 있는지 확인하고 없을경우 using System.Collections.Generic; 처럼 해당클래스의 네임스페이스를 직접 추가하면 된다.

 

 

 

***숙제 : 그림1의 소스에 대한 주석을 달아보자. 아래 StringBuilder 와 string 의 속도차이를 비교할수있는 프로그램도 만들어보자.

'[ Program ] > c#스터디' 카테고리의 다른 글

43. 제네릭  (0) 2021.10.09
42. 상속  (0) 2021.10.09
40.using/garbage collection  (0) 2021.10.09
39.property(속성)  (0) 2021.10.09
38.const/enum/struct  (0) 2021.10.09

댓글