1. 함수형 프로그래밍
- Functional Programming
- 함수형 프로그래밍은 프로그래밍 패러다임 중 하나로, 함수를 값으로 다루는 프로그래밍을 말한다.
1void main() {2List<String> blackPink = ['로제', '제니', '리사', '지수'];34print(blackPink); // [로제, 제니, 리사, 지수]5print(blackPink.asMap()); // {0: 로제, 1: 제니, 2: 리사, 3: 지수}6print(blackPink.toSet()); // {로제, 제니, 리사, 지수}78// Map9Map blackPinkMap = blackPink.asMap();10print(blackPinkMap.keys); // (0, 1, 2, 3)11print(blackPinkMap.values); // (로제, 제니, 리사, 지수)1213// Set14Set blackPinkSet = Set.from(blackPink);1516// Set to List17print(blackPinkSet.toList()); // [로제, 제니, 리사, 지수]18}
2. list 관련 함수
2.1 map
1void main() {2List<String> blackPink = ['로제', '제니', '리사', '지수'];34final newBlackPink = blackPink.map((element) {5return '블랙핑크 $element';6});78print(blackPink); // ['로제', '제니', '리사', '지수']9print(newBlackPink.toList()); // ['블랙핑크 로제', '블랙핑크 제니', '블랙핑크 리사', '블랙핑크 지수']1011final newBlackPink2 = blackPink.map((element) => '블랙핑크 $element');12print(newBlackPink2.toList()); // ['블랙핑크 로제', '블랙핑크 제니', '블랙핑크 리사', '블랙핑크 지수']1314// map을 쓰면 새로운 Iterable을 반환하기 때문에 == 연산자로 비교하면 항상 false가 나온다.15print(blackPink == blackPink); // true16print(blackPink == newBlackPink); // false17print(newBlackPink == newBlackPink2); // false18}
2.2 split
1void main() {2String number = '13579';34final parsed = number.split('').map((element) => '$element.jpg').toList();56print(parsed); // [1.jpg, 3.jpg, 5.jpg, 7.jpg, 9.jpg]7}
2.3 Map
1void main() {2Map<String, String> haryyPotter = {3'Harry Potter': '해리 포터',4'Ron Weasley': '론 위즐리',5'Hermione Granger': '헤르미온느 그레인저',6};78// MapEntry : Map의 key와 value를 담는 클래스9final result = haryyPotter.map(10(key, value) => MapEntry(11'Hearry Potter Character $key',12'해리포터 캐릭터 $value'13),14);1516print(haryyPotter);17print(result);1819final keys = haryyPotter.keys.map((e) => 'HPC $e').toList();20final values = haryyPotter.values.map((e) => '해리포터 $e').toList();21print(keys);22print(values);23}
2.4 Set
1void main() {2Set blackPinkSet = {'로제', '제니', '리사', '지수'};34final newSet = blackPinkSet.map((e) => '블랙핑크 $e').toSet();56print(newSet);7}
2.5 where
1void main() {2List<Map<String, String>> people = [3{'name': '로제', 'group': '블랙핑크'},4{'name': '지수', 'group': '블랙핑크'},5{'name': '사나', 'group': '트와이스'},6{'name': '다현', 'group': '트와이스'},7];89print(people);1011// where : 조건에 맞는 요소만 추출12final blackPink = people.where((el) => el['group'] == '블랙핑크').toList();13final twice = people.where((el) => el['group'] == '트와이스').toList();1415print(blackPink);16print(twice);17}
2.6 reduce
1void main() {2List<int> numbers = [1, 3, 5, 7, 9];34// prev : 이전 함수를 실행한 결과 값, 맨 처음은 리스트의 첫번째 값5// next : 다음 요소 값6final result = numbers.reduce((prev, next) {7print('-------------------------------');8print('previous: $prev');9print('next: $next');10print('total: ${prev + next}');1112return prev + next;13});1415print(result);16}
위 코드를 축약하고, 추가적인 예제를 보자.
1void main() {2List<int> numbers = [1, 3, 5, 7, 9];34final result = numbers.reduce((prev, next) => prev + next);56print(result);78List<String> words = [9'안녕하세요',10'반갑습니다',11'다트 언어',12];1314final sentence = words.reduce((prev, next) => prev + next);1516print(sentence);1718// 📌 reduce는 멤버들의 타입과 같은 타입을 return해줘야지만 실행 가능하다.19// words.reduce((prev, next) => prev.length + next.length); // Error20}
2.7 fold
- reduce의 멤버들의 타입과 같은 타입을 return해줘야지만 실행 가능한 부분을 제거한 것이 fold다.
- fold는 초기값을 지정할 수 있다.
1void main() {2List<int> numbers = [1, 3, 5, 7, 9];34// fold : 맨 처음 시작시 초기값을 설정할 수 있음5// 여기서는 0을 맨 처음 초기값으로 설정함6final sum = numbers.fold<int>(0, (prev, next) {7print('-------------------------------');8print('previous: $prev');9print('next: $next');10print('total: ${prev + next}');1112return prev + next;13});1415print(sum); // 2516}
위 코드를 축약하고, 추가적인 예제를 보자.
1void main() {2List<int> numbers = [1, 3, 5, 7, 9];34// fold : 맨 처음 시작시 초기값을 설정할 수 있음5// 여기서는 0을 맨 처음 초기값으로 설정함6final sum = numbers.fold<int>(0, (prev, next) => prev + next);78print(sum); // 25910List<String> words = ['hello', 'world', 'dart'];1112final sentence = words.fold<String>('', (prev, next) => prev + next);13print(sentence); // hello world dart1415final count = words.fold<int>(0, (prev, next) => prev + next.length);16print(count); // 1517}
2.8 cascading operator
cascade operator(연쇄 연산자): 펼침 연산자로도 불린다.- 완전히 새로운 리스트에다가 값을 풀어서 추가할 수 있다.
1void main() {2List<int> even = [2, 4, 6, 8];3List<int> odd = [1, 3, 5, 7];45print([...even, ...odd]); // [2, 4, 6, 8, 1, 3, 5, 7]6print(even); // [2, 4, 6, 8]7print([...even]); // [2, 4, 6, 8]8print(even == [...even]); // false9}
3. 함수형 프로그래밍 예제
1void main() {2List<Map<String, String>> people = [3{'name': '로제', 'group': '블랙핑크'},4{'name': '지수', 'group': '블랙핑크'},5{'name': '사나', 'group': '트와이스'},6{'name': '다현', 'group': '트와이스'},7];89print(people);1011final parsedPeople = people.map(12(e) => Person(13name: e['name']!, // !는 null 이 아님을 보장14group: e['group']!,15),16).toList();1718print(parsedPeople);1920for(Person p in parsedPeople) {21print(p.name);22print(p.group);23}2425final twices = parsedPeople.where((p) => p.group == '트와이스').toList();26print(twices);2728final result = people.map(29(e) => Person(30name: e['name']!,31group: e['group']!,32),33).where((p) => p.group == '트와이스').toList();34print(result);35}3637class Person {38final String name;39final String group;4041Person({42required this.name,43required this.group,44});4546@override47String toString() {48return 'Person(name: $name, group: $group)';49}50}
- 어떤 데이터든 데이터를 다루게 되면, 꼭 구조화를 해가지고 클래스 형태로 다루게 된다.
3.1 함수형 프로그래밍 특징
- 실행하는 그 대상 리스트나 세트나 맵과 완전히 다른 새로운 값을 생성해준다.
- 체이닝을 할 수가 있다.
체이닝: 여러 개의 함수들을 연결해서 사용하는 것- 여러 개의 함수들을 체이닝 해가지고 새로운 값을 만들어내면서 매번 새로운 값을 만들 수 있음
- 함수형 프로그래밍을 하는 굉장히 큰 이유 중 하나가 코드가 간결해지기 때문이다.
- 그런데 여기에 너무 심취해 가지고 너무 많이 연동을 해버리면,
- 다른 사람들과 협업을 할 때에는 코드를 이해하기가 어려워진다.
- 그렇기 때문에 진짜 필요한 기능들만 따로따로 작성을 하고서 코멘트를 달아 준다던가
- 또는 조금 잘라가지고 잘라가지고 작성을 한다던가 라는 습관을 갖는 것이 좋다.