
고차 함수
함수를 다루는 함수.
collection 타입의 데이터에 있는 요소를 처리하거나 변환할 때 사용..map()
collection 타입인 데이터의 각 요소에 특정 함수를 적용한 새로운 collection 타입의 데이터를 반환한다.
void main() {
List<String> directorsList = ["박찬욱", "봉준호", "홍상수", "나홍진"];
var krepresented = directorsList.map((director) {
var modiflier = '한국을 대표하는 영화감독 ';
modiflier += director;
return modiflier;
});
print("$krepresented, ${krepresented.runtimeType}");
}
// (한국을 대표하는 영화감독 박찬욱, 한국을 대표하는 영화감독 봉준호, 한국을 대표하는 영화감독 홍상수, 한국을 대표하는 영화감독 나홍진), MappedListIterable<String, String>void main() {
List<int> numbers = [1,2,3,4,5];
var plusFive = numbers.map((number) {
number += 5;
return number;
});
print("$plusFive, ${plusFive.runtimeType}");
} // (6, 7, 8, 9, 10), MappedListIterable<int, int>TIL : 고차함수 좀 더 이해하기 - Iterable
위의 예시를 다시 가져와보자.
void main() {
List<int> numbers = [1,2,3,4,5];
var plusFive = numbers.map((number) {
number += 5;
return number;
});
print("$plusFive, ${plusFive.runtimeType}");
} // (6, 7, 8, 9, 10), MappedListIterable<int, int>plusFive의 runtimeType이 MappedListIterable<int, int>로 나왔길래‘아무튼 List라는 거지?’ 싶어서
plusFive[2] 를 프린트해보았는데 - 에러가 났다.void main() {
List<int> numbers = [1,2,3,4,5];
var plusFive = numbers.map((number) {
number += 5;
return number;
});
print("$plusFive, ${plusFive.runtimeType}");
print(plusFive[2]);
} // The operator '[]' isn't defined for the type 'Iterable<int>'.왜죠?! GPT 센세에게 다시 여쭤본다.
1. 개념 요약
Iterable = “순차적으로 하나씩 꺼낼 수 있는 값들의 집합을 나타내는 추상 타입”
즉,
“앞에서부터 차례대로 반복될 수 있는 것”을 의미하는 추상적 타입(인터페이스)
List, Set 같은 컬렉션의 상위 타입(부모 타입)
반복문(for-in)에서 하나씩 꺼낼 수 있으면 다 Iterable
2. 인덱스 호출 실패 이유
Iterable은 List의 상위 타입으로, index를 갖지 않는다.
3. Further information
map(), where(), reduce() 등 컬렉션 함수형 메서드는 모두 Iterable을 반환한다.
만약 컬렉션 함수형 메서드의 반환값을 List로 변환하고 싶다면 .toList를 사용할 것.아하. 그렇구만.
내가 이해한대로 다시 정리하자면, 함수를 다루는 함수, 즉 고차함수의 경우, List, Map, Set과 같은 하위 타입의 함수를 Iterable이라는 상위 타입의 차원에서 다룬다는 것 같다.
⇒ GPT 센세의 최종 정리는 다음과 같다:
고차 함수는 List, Set, Map을 직접 다루는 것이 아니라, 이 컬렉션들이 Iterable을 구현하고 있기 때문에, Iterable 차원에서 공통적으로 동작한다. == 고차함수는 Iterable이라는 상위타입이 제공하는 공통 규약에 따라 List, Set과 같은 하위 타입을 일관되게 다룬다.
그래서 고차함수 라고 하는 구나. 이해했다.
map().toList를 활용하여 새로운 Map 만들기
map()을 적용하면 Iterable 타입이 된다는 것을 이해한 후, 다시 map()을 활용하며 놀기를 이어갔다.List 에 적용했으니 Set에는 당연히 적용 될 테니 건너뛰고,
이제 Map타입에도 map() 함수를 적용하고 싶은 생각이 든 거다.trial 1. value의 인덱스를 교체해보자.
void main() {
Map<String, int> beers = {"생맥주":5000, "빅웨이브":8000, "듀체스":14000};
var beerBrand = beers.keys.map((beer) {
return ("비앤타 명물 $beer");
});
var beerPrice = beers.values.map((beer) {
return ("$beer원");
});
var beerPriceMarkup = beers.values.map((beer) {
return (beer += 1000);
});
print(beerBrand);
print(beerPrice);
print(beerPriceMarkup);
/*Map<String, int> beerNewPrice (int price) {
int count = 0;
while (count < beers.length) {
return beers[]
}
}*/ // The operator '[]' isn't defined for the type 'Iterable<int>'.
}내가 뭘 하고 싶었는지 알겠나?
나는 비앤타의 맥주 가격을 1000원씩 인상하여
beerNewPrice라는 이름의 새로운 Map을 만들고 싶었다.이 발상의 핵심은 beers라는 Map 타입 데이터에서 values 에 해당하는 인덱스를 호출하여 인상된 가격의 인덱스로 변환하려고 했다는 점이다.
그러나 어떻게 해도 에러가 잡히질 않았다. 결국 또 GPT행..
그리고 내가 여기서 또 헤맸다는 사실에 충격을 먹었다….
아까 map()은 Iterable 타입으로 반환된다매! Iterable 타입은 인덱스 없다매!!
아니… 방금 확인했던 건데 어쩜 이렇게 싹 까먹고;;
사실 방금은 아니고, 한 시간 전 쯤 확인한 거긴 한데… 아니 그래도…
암튼 뭐 이렇게 한 번 더 배운 거지!
그렇다면, 나는 뭘 어떻게 했어야 했을까?
trial 2. beers.values.map().toList로 바꿔보자!
void main() {
Map<String, int> beers = {"생맥주":5000, "빅웨이브":8000, "듀체스":14000};
var beerBrand = beers.keys.map((beer) {
return beer;
}).toList();
var beerPriceMarkup = beers.values.map((beer) {
return (beer += 1000);
}).toList();
print(beerBrand);
print(beerPriceMarkup);
Map<String, int> beersNewPrice = {};
int count = 0;
while (count < beers.length) {
beersNewPrice["${beerBrand[count]}"] = beerPriceMarkup[count];
count++;
}
print(beersNewPrice);
}
/*
[생맥주, 빅웨이브, 듀체스]
[6000, 9000, 15000]
{생맥주: 6000, 빅웨이브: 9000, 듀체스: 15000}
*/.toList를 활용하여Iterable타입 데이터에index를 부여하고,
- 비어있는 맵
beersNewPrice를 생성한 후,
Map name[key] = value;를while문으로 반복하여 빈 맵에 요소를 추가하여
⇒ 새로운 메뉴판을 완성한 것이다!!
개 미쳐버려.
너무 잘했다.
이 최종 코드를 쓰는 데에는 GPT선생의 도움을 받지 않았다.
이렇게 뿌듯할 수가😊
map.entries — further
다 만들고 나서 GPT선생에게 자랑하니, 더 좋은 걸 알려주겠다신다 ㅋㅋㅋㅋㅋㅋㅋㅋㅋ
집에 보내주세요…
오늘은 일단 적어만 놓고, 내일 이어서 다시 봐야징 😈
GPT선생의 보너스 학습 — map.entries
[1] 개념 요약
map.entries = Map 안의 요소들을 MapEntry(key, value) 형태로 모아 둔 Iterable- 각각의 요소는 키 + 값 한 쌍인
MapEntry<K, V>타입
- 그래서
entry.key,entry.value로 하나의 쌍에 접근 가능
entries자체는 Iterable이라서,for-in으로 돌리거나.toList()로 리스트로 바꿔서 index 접근 가능
[2] PDF 기반 맥락 잡기
PDF 챕터1-8 (컬렉션 2) 에서 Map을 이렇게 설명했어요:
- Map은 키(key)와 값(value)이 묶인 하나의 쌍으로 이루어진 구조
people['Alice']처럼 키로 값에 접근
map.keys,map.values로 각각 모든 키/모든 값에 접근
여기까지가 강의 PDF에 있는 내용이고,
entries는 "키와 값이 묶여 있는 한 쌍"을 직접 다루는 더 고급 API라고 보면 됩니다.(이 아래부터는 “강의 외 확장 설명입니다” 👇)
[3] 예제 코드로 보는 entries 활용
질문에서 주신 예제에
entries를 붙여볼게요.void main() {
Map<String, int> beers = {
"생맥주": 5000,
"빅웨이브": 8000,
"듀체스": 14000,
};
// 1) entries 기본 형태
var entries = beers.entries;
print(entries.runtimeType);
// (Iterable<MapEntry<String, int>> 이런 식으로 나옴)
// 2) for-in 으로 key, value 한 번에 꺼내기
for (var entry in beers.entries) {
print('메뉴: ${entry.key}, 가격: ${entry.value}');
}
// 3) entries 를 List 로 변환해서 index 사용하기
var entryList = beers.entries.toList();
print(entryList[0].key); // 0번째 키
print(entryList[0].value); // 0번째 값
// 4) map() 같이 고차함수에도 활용 가능
var menuStrings = beers.entries.map((entry) {
return '${entry.key}는 ${entry.value}원';
}).toList();
print(menuStrings);
// [생맥주는 5000원, 빅웨이브는 8000원, 듀체스는 14000원]
}여기서 포인트는:
beers.entries→ Iterable<MapEntry<String, int>>
- 각
entry는entry.key/entry.value로 접근
[4] 추가 설명 (강의 외 확장 설명입니다)
1️⃣ keys / values vs entries
방법 | 설명 | 언제 쓰기 좋냐 |
map.keys | 키들만 Iterable | “메뉴 이름만 필요할 때” |
map.values | 값들만 Iterable | “가격만 필요할 때” |
map.entries | MapEntry(key, value) 쌍들의 Iterable | “키와 값을 동시에 다루고 싶을 때” |
예를 들어 가격 순으로 정렬해서 출력하고 싶다면
entries가 엄청 편합니다:void main() {
Map<String, int> beers = {
"생맥주": 5000,
"빅웨이브": 8000,
"듀체스": 14000,
};
var sortedByPrice = beers.entries.toList()
..sort((a, b) => a.value.compareTo(b.value));
for (var entry in sortedByPrice) {
print('${entry.key} : ${entry.value}원');
}
}여기서:
entries.toList()→ 리스트로 만들어서 sort 사용
a.value,b.value로 가격 기준 정렬
- 키와 값 둘 다 필요하니까
entries가 제일 깔끔함
[5] 학생 눈높이 비유
map.keys는 “메뉴 이름만 쭉 뽑은 명단”
map.values는 “가격만 쭉 뽑은 명단”
map.entries는
“각 줄에 메뉴 + 가격 같이 있는 엑셀 행들”
그래서
entries를 쓰면- “이 메뉴의 가격이 1만 원 넘으면 ~”
- “가격순으로 메뉴를 정렬해서 출력해줘”
- “메뉴 이름 + 가격을 합쳐서 문자열 만들기”
같이 키와 값이 동시에 필요한 작업이 훨씬 편해집니다.
정리하면:
“Map에서 key, value 둘 다 다뤄야 하는 상황이면entries로 시작해서.key,.value를 쓰는 패턴을 떠올리면 된다!”
다음으로,
entries에 where, map, fold 같은 고차함수 조합해서실전 패턴도 보고 싶으면 그쪽도 예제를 만들어 줄게요 💪
Share article