Map은 키와 값을 한쌍으로 저장하는 컬렉션 입니다.
Map<Key Type, Value Type>
Map<String, String>
Map<String, int>
특징
- 키 값은 중복이 없어야 함
- 키 하나에 값 하나만 연결(매핑)
- 키(key) 타입과 값(value) 타입은 같게 혹은 다르게 설정이 가능
기본적인 Map 생성 방법은 다음과 같습니다.
var mapDefault = <String, int>{};
var mapDynamic = {}; // Map<dynamic, dynamic> 으로 추론됨
// 명시적으로 타입을 선언한 형태
var mapDefault = <String, int>{ "apple" : 1, "banana" : 2};
// 암묵적으로 타입을 선언하지 않은 형태
var mapDynamic = {"apple" : 1, "banana" : 2};
Map for 문 사용한 탐색 방법
기본 Map
Map<String, int> scores = {'Alice': 90, 'Bob': 85, 'Charlie': 95};
forEach
scores.forEach((key, value) {
print('$key: $value');
});
for - key
for (var key in scores.keys) {
print('key: $key');
}
for - value
for (var value in scores.values) {
print('value: $value');
}
for - entry
for (var entry in scores.entries) {
print('key : ${entry.key}');
print('value : ${entry.value}');
}
기본적인 Map 의 종류는 크게 3가지로 나뉘며 일반적으로 사용하는 Map 의 구현체는 LinkedHashMap 입니다.
- LinkedHashMap
- 키의 삽입 순서를 유지하는 Map
- 일반 Map은 키의 순서가 보장되지 않지만, LinkedHashMap은 입력된 순서대로 키를 관리
- HashMap
- 해시 테이블을 기반으로 구현된 Map
- 키의 해시 값을 사용하여 데이터를 저장하므로, 키를 기반으로 한 검색 속도가 빠름
- SplayTreeMap
- 자체적으로 균형을 유지하는 트리 기반의 Map
- 특정 키에 접근할 때마다 해당 키가 트리 구조의 상위 노드로 이동하므로, 최근에 사용된 키에 대한 접근 속도가 빨라짐
위에서 언급했듯이 일반적으로 Map 리터럴({})의 기본 구현체로 LinkedHashMap 을 사용합니다. 즉 Map<String, int> map = {’a’ : ‘a’, … }; 와 같이 작성한다면 {’a’ : ‘a’, … } 은 LinkedHashMap 입니다.
예를 들어서 다음과 같이 Map 을 만들 경우에
Map<String, int> person = {'Alice': 30, 'Bob': 25, 'Charlie': 50};
위 코드가 내부적으로는 아래와 같이 LinkedHashMap 을 사용하는 것과 동일한 효과를 갖습니다.
Map<String, int> personMap = LinkedHashMap.from({'Alice': 30, 'Bob': 25, 'Charlie': 50});
Dart에서는 Map 리터럴 ({})의 기본 구현체로 LinkedHashMap 을 사용합니다.
Map의 순서 에 대해서
Map 의 경우 LinkedHashMap 순서를 유지하지만 HashMap 의 경우 순서를 신뢰할 수 없습니다. 별도의 추가적인 작업을 하지 않는 Map 을 구현할 경우에는 LinkedHashMap 을 사용하기 때문에 순서를 가진 형태로 데이터를 출력할 수 있습니다.
조금 더 자세히 설명을 하자면 LinkedHashMap 의 경우 내부적으로는 Hash Table 과 Linked List 를 모두 사용하는 구현체입니다. HashMap 의 단점인 순서를 보장하면서 List 의 단점인 검색이 느린 부분을 보완해서 나온 형태라고 보면 됩니다.
내부적으로는 HashTable, LinkedList 을 사용해서 데이터를 빠르게 검색(O(1))하거나 순차적으로 데이터를 출력할 수 있습니다. 다만, LinkedHashMap 이 슈퍼파워를 가진 구현체는 아닙니다. 당연하게도 Trade-off 를 해야합니다. HashMap 사용할때보다는 데이터 저장에 시간이 조금 더 소요(약 5~20% 증가)되고 메모리도 조금 더 사용(약 20~40% 증가)하게 됩니다.
아래와 같이 Map 을 만들었을 경우에 내부적으로 어떻게 데이터가 저장되는지 확인해보시면 좋겠습니다.
Map
final map = {'apple' : 1, 'banana' : 2, 'cherry' : 3 };
Hash Table
Index | Entry
------+----------------------------
0 | null
1 | null
2 | null
3 | [Entry(key='banana', value=2)]
4 | null
5 | [Entry(key='apple', value=1)]
6 | null
7 | null
8 | null
9 | [Entry(key='cherry', value=3)]
Doubly Linked List
head
↓
[Entry(key='apple', value=1)]
↕
[Entry(key='banana', value=2)]
↕
[Entry(key='cherry', value=3)]
↑
tail
Map 을 List 만들기
값만 리스트로 | map.values.toList() |
키만 리스트로 | map.keys.toList() |
객체 리스트로 | map.entries.map((e) => MyClass(e.key, e.value)).toList() |
MapEntry 리스트로 | map.entries.toList() |
forEach로 직접 추가 | map.forEach((k, v) => list.add(MyClass(k, v))); |
Map 자체만 가지고는 List 로 변경이 불가능 합니다. Map 에 존재하는 Iterable 구현체 요소들(keys, values, entries) 를 통해서 만들수가 있습니다.
class Person {
String name;
int age;
Person(this.name, this.age);
}
void main() {
Map<String, int> personMap = {'Alice': 30, 'Bob': 25, 'Charlie': 50};
List<Person> personList = personMap.entries
.map((e) => Person(e.key, e.value))
.toList();
}
'Dev > Flutter' 카테고리의 다른 글
[강의자료] Json 무엇이고 Dart 에서 어떻게 사용할까? (3) | 2025.07.25 |
---|---|
Android Emulator 안드로이드 에뮬레이터 Light, Dark 모드 전환 (0) | 2025.07.16 |
Flutter 빌드 오류 (0) | 2025.06.16 |
Flutter iOS Android 폴더 생성 (0) | 2025.06.08 |
[Flutter] Could not locate aapt. Please ensure you have the Android buildtools installed. (0) | 2025.05.13 |