List 는 칸이 모자라면 알아서 늘린다
배열은 만들 때 칸 개수가 정해지고 그 뒤로 안 바뀝니다. 개수를 미리 아는 것은 괜찮습니다. 문제는 모를 때입니다.
사용자가 입력하는 대로 담아야 한다면 몇 칸을 잡아야 할까요. 앞에서 본 방식대로 넉넉하게 잡을 수는 있습니다.
int[] nums = new int[1000];
int count = 0; // 지금 몇 개 들어 있는지 따로 세야 합니다
칸 1000개를 잡아 두고 3개만 쓰면 997칸이 놀고, 1001개가 들어오면 터집니다.
그리고 몇 개가 들어 있는지를 변수로 따로 관리해야 합니다.
nums.Length 는 1000이지 3이 아니니까요.
칸이 모자라면 알아서 늘리고, 개수도 스스로 세는 것이
List입니다.
List 는 이렇게 생겼다
using System.Collections.Generic;
List<int> nums = new List<int>();
nums.Add(90);
nums.Add(85);
nums.Add(78);
Console.WriteLine(nums.Count); // 3
Console.WriteLine(nums[1]); // 85
List<int> 의 꺾쇠 안이 담을 타입입니다.
List<string>, List<double> 처럼 바꿔 쓰면 됩니다.
이 꺾쇠 문법의 정체는 나중에 제네릭에서 다룹니다.
지금은 “담을 타입을 적는 자리” 정도로 보면 충분합니다.
배열과 다른 점이 두 가지 보입니다.
- 만들 때 칸 개수를 안 적습니다.
- 개수가
Length가 아니라Count입니다. 그리고 실제로 들어 있는 개수입니다.
꺼내는 것은 배열과 똑같이 대괄호에 번호입니다. 인덱스도 0부터입니다.
| 하는 일 | 배열 | List |
|---|---|---|
| 만들기 | new int[3] |
new List<int>() |
| 개수 | Length (칸 수) |
Count (들어 있는 수) |
| 꺼내기 | a[0] |
list[0] |
| 넣기 | a[0] = 5 |
list.Add(5) |
| 빼기 | 없음 | list.RemoveAt(0) |
속은 그냥 배열이다
List 가 마법을 부리는 것은 아닙니다. 안에 배열을 하나 들고 있습니다.
칸이 꽉 찼는데 하나를 더 넣으라고 하면, 앞 글 마지막에서 우리가 손으로 했던 일을 그대로 합니다. 더 큰 배열을 새로 만들고, 전부 옮겨 담고, 새 배열을 쓰기 시작합니다.
늘릴 때 두 배로 잡는 것이 요령입니다. 한 칸씩만 늘리면 Add 할 때마다
전부 옮겨야 해서 앞에서 본 문자열 + 와 같은 꼴이 납니다.
두 배로 잡으면 옮기는 일이 점점 드물게 일어나서,
평균으로 보면 Add 하나가 거의 공짜에 가까워집니다.
몇 개쯤 들어올지 짐작이 되면 미리 알려줄 수도 있습니다.
List<int> nums = new List<int>(1000); // 처음부터 1000칸 잡고 시작
이건 칸 개수를 정하는 게 아니라 처음에 잡을 크기를 알려주는 것입니다. 1001개를 넣어도 터지지 않고 알아서 늘어납니다. 옮기는 일을 줄여 줄 뿐입니다.
중간에 넣고 빼면 밀린다
List 는 중간에 끼워 넣거나 빼는 것도 됩니다.
nums.Insert(0, 100); // 맨 앞에 끼워 넣기
nums.RemoveAt(0); // 첫 칸 빼기
편해 보이는데 공짜가 아닙니다. 배열은 칸이 빈틈없이 붙어 있어야 하니까, 맨 앞에 하나 끼워 넣으면 뒤의 모든 값이 한 칸씩 밀려야 합니다. 빼면 반대로 한 칸씩 당겨집니다.
들어 있는 개수만큼 움직입니다. 위 그림에서 옮긴 칸 수를 보세요. 맨 뒤는 0이고 맨 앞은 들어 있는 만큼입니다.
| 하는 일 | 비용 |
|---|---|
list[i] 로 꺼내기 |
어디를 꺼내든 같다 |
맨 뒤에 Add |
대부분 그냥 한 칸 채운다 |
중간이나 앞에 Insert / RemoveAt |
뒤에 있는 것들이 전부 밀린다 |
만 개짜리 리스트의 맨 앞을 반복문 안에서 계속 지우고 있다면, 그건 겉보기와 달리 무거운 코드입니다.
배열이냐 List 냐
개수가 변하면 List, 고정이면 배열입니다.
요일 7개, 바둑판 19 × 19 처럼 개수가 처음부터 정해진 것은 배열이 맞습니다. 개수가 코드에 적혀 있으니 읽는 사람도 “여기는 안 늘어난다” 를 압니다.
인벤토리, 접속한 사용자 목록처럼 실행 중에 개수가 변하는 것은 List 입니다.
배열로 하면 결국 List 가 해 주는 일을 손으로 다시 만들게 됩니다.
애매하면 List 를 쓰면 됩니다. 실무에서 훨씬 자주 씁니다.
정리
List는 칸이 모자라면 알아서 늘어나고, 들어 있는 개수를Count로 알려줍니다.- 꺾쇠 안이 담을 타입입니다. 꺼내는 것은 배열과 똑같이 대괄호에 번호입니다.
- 속은 배열입니다. 꽉 차면 두 배 크기로 새로 만들어 전부 옮깁니다.
- 두 배로 늘리기 때문에 옮기는 일이 드물게 일어납니다.
Add는 대체로 싸게 끝납니다. - 중간이나 앞에 넣고 빼면 뒤가 전부 밀립니다. 이건 싼 연산이 아닙니다.
- 개수가 변하면
List, 고정이면 배열입니다.