Dart 함수형 프로그래밍

원종인·2022년 6월 23일
0

Dart 공부

목록 보기
3/4

형변환

.asMap()을 사용하면 Map으로 형변환이 가능하다. 이때 key는 리스트의 인덱스이고, value가 리스트의 값이다.
.toSet()을 사용하면 Set으로 형변환이 가능하다. 이때 리스트에서 중복된 값이 있다면 삭제된다.

void main() {
  List<String> blackPink = ["로제","지수","리사","제니","제니"];
  
  print(blackPink);
  print(blackPink.asMap());
  print(blackPink.toSet());
}
<결과>
[로제, 지수, 리사, 제니, 제니]
{0: 로제, 1: 지수, 2: 리사, 3: 제니, 4: 제니}
{로제, 지수, 리사, 제니}

Map에서 .keys를 사용하면 키값을, .values를 사용하면 밸류값을 가져온다. 근데 이때 결과를 보면 ()로 나옴을 알 수 있다.
()는 Iterable이라는 형태이며 리스트와 유사하다. 근데 해당 형태는 리스트, 맵, 세트로 변환하기 쉽기위해 만들어졌고 실제로는 잘 사용하지 않는다.

  Map blackPinkMap = blackPink.asMap();
  print(blackPinkMap.keys);
  print(blackPinkMap.values);
<결과>
(0, 1, 2, 3, 4)
(로제, 지수, 리사, 제니, 제니)

이를 리스트로 다시 만들기 위해서는 .toList()를 사용하면 된다.

  Map blackPinkMap = blackPink.asMap();
  print(blackPinkMap.keys.toList());
  print(blackPinkMap.values.toList());
<결과>
[0, 1, 2, 3, 4]
[로제, 지수, 리사, 제니, 제니]

리스트를 Set로 만드는 방법은 두가지인데 위에서 사용했던 .toSet()를 사용하거나 Set.from(리스트)를 사용하는 것이다.
그리고 set를 다시 list로 만들려면 .toList()를 사용하면 된다.

void main() {
  List<String> blackPink = ["로제", "지수", "리사", "제니", "제니"];

  Set blackPinkSet1 = blackPink.toSet();
  Set blackPinkSet2 = Set.from(blackPink);
  
  print(blackPinkSet1.toList());
}

List

map 메소드를 사용하면 쉽게 프로그래밍을 할 수 있다. 이때 Map이랑은 다른 것을 염두해두어야 한다.!!
리스트.map((x){});이런 형태로 이루어지는데 x에는 각 리스트의 멤버를 받게 된다. 즉 blackPink에서 로제,지수,리사,제니를 돌아가면서 받게된다는 뜻
그리고 return하면 x를 대체하게 된다. 그렇지만 blackPink를 변경하는것이 아닌 새로 만들어서 적용시켜줘야 한다. 이때 Iterable 형태로 반환되기에 .toList()를 사용해서 변형해주어야 한다.

void main() {
  List<String> blackPink = ["로제", "지수", "리사", "제니", "제니"];

  final newBlackPink = blackPink.map((x){
    return "블랭핑크 $x";
  });
  
  print(blackPink);
  print(newBlackPink);
}
<결과>
[로제, 지수, 리사, 제니, 제니]
(블랭핑크 로제, 블랭핑크 지수, 블랭핑크 리사, 블랭핑크 제니, 블랭핑크 제니)

이때 Iterable 형태로 반환되기에 .toList()를 사용해서 변형해주어야 한다.

void main() {
  List<String> blackPink = ["로제", "지수", "리사", "제니", "제니"];

  final newBlackPink = blackPink.map((x){
    return "블랭핑크 $x";
  }).toList();
  
  print(blackPink);
  print(newBlackPink);
}
<결과>
[로제, 지수, 리사, 제니, 제니]
[블랭핑크 로제, 블랭핑크 지수, 블랭핑크 리사, 블랭핑크 제니, 블랭핑크 제니]

위의 함수를 더 간단히 사용하는 방법도 있다. 애로우 함수를 사용하면 더 간결해진다.

void main() {
  List<String> blackPink = ["로제", "지수", "리사", "제니", "제니"];

  final newBlackPink = blackPink.map((x){
    return "블랭핑크 $x";
  }).toList();
  
  final newBlackPink2 = blackPink.map((x) => "블랙핑크 $x");
  
  print(newBlackPink); 
  print(newBlackPink2); 
}
<결과>
[블랭핑크 로제, 블랭핑크 지수, 블랭핑크 리사, 블랭핑크 제니, 블랭핑크 제니]
(블랙핑크 로제, 블랙핑크 지수, 블랙핑크 리사, 블랙핑크 제니, 블랙핑크 제니)

이것도 .toList()를 사용하여 List로 변경해주면 된다.

void main() {
  List<String> blackPink = ["로제", "지수", "리사", "제니", "제니"];

  final newBlackPink = blackPink.map((x){
    return "블랭핑크 $x";
  }).toList();
  
  final newBlackPink2 = blackPink.map((x) => "블랙핑크 $x").toList();
  
  print(newBlackPink); 
  print(newBlackPink2); 
}
<결과>
[블랭핑크 로제, 블랭핑크 지수, 블랭핑크 리사, 블랭핑크 제니, 블랭핑크 제니]
[블랙핑크 로제, 블랙핑크 지수, 블랙핑크 리사, 블랙핑크 제니, 블랙핑크 제니]

여기서 map을 사용하면 새로운 리스트가 만들어지기에 newBlackPink와 newBlackPink2는 다른 리스트다.!!!

<많이 사용하는 예시>

void main() {
  String number = "13579";
  final parsed = number.split("").map((x) => "$x.jpg").toList();
  print(parsed);
}
<결과>
[1.jpg, 3.jpg, 5.jpg, 7.jpg, 9.jpg]

Map

맵 또한 리스트처럼 map를 통해서 각 키와 값을 변경할 수 있다.
그런데 해당 방법은 잘 사용하지 않는다.

void main() {
  Map<String, String> harryPotter = {
    "Harry Potter": "해리 포터",
    "Ron Weasley": "론 위즐리",
    "Hermione Granger": "헤르미온느 그레인저"
  };

  final result = harryPotter.map((key, value) =>
      MapEntry(
        "Harry Potter Character $key", 
        "해리포터 캐릭터 $value"
      )
  );
  
  print(result);
}
<결과>
{Harry Potter Character Harry Potter: 해리포터 캐릭터 해리 포터, Harry Potter Character Ron Weasley: 해리포터 캐릭터 론 위즐리, Harry Potter Character Hermione Granger: 해리포터 캐릭터 헤르미온느 그레인저}

키 값, 벨류 값을 리스트로 변경하고 싶을 때 많이 사용

void main() {
  Map<String, String> harryPotter = {
    "Harry Potter": "해리 포터",
    "Ron Weasley": "론 위즐리",
    "Hermione Granger": "헤르미온느 그레인저"
  };
  
  final keys = harryPotter.keys.map((x)=> "HPC $x").toList();
  final values = harryPotter.values.map((x)=> "해리포터 $x").toList();
  
  print(keys);
  print(values);
}
<결과>
[HPC Harry Potter, HPC Ron Weasley, HPC Hermione Granger]
[해리포터 해리 포터, 해리포터 론 위즐리, 해리포터 헤르미온느 그레인저]

Set

세트도 map을 통해서 새로운 세트를 만들 수 있다.

void main() {
  Set blackPink = {
    "로제",
    "지수",
      "제니",
    "리사"
  };
  
  final newSet = blackPink.map((x)=>"블랙핑크 $x").toSet();
  
  print(newSet);
}
<결과>
{블랙핑크 로제, 블랙핑크 지수, 블랙핑크 제니, 블랙핑크 리사}

where

.where()는 map과 작동방식은 유사하다. 괄호 안에 함수를 넣어주면 된다.
각각의 멤버들을 돌면서 true 또는 false를 반환한다. 이때, true면 유지하고, false면 제거한다. 물론 실제 변수에서 제거하는 것은 아니기에 해당 결과는 새로운 변수로 받아야 한다.

void main() {
  List<Map<String, String>> people = [
    {"name": "로제", "group": "블랙핑크"},
    {"name": "지수", "group": "블랙핑크"},
    {"name": "RM", "group": "BTS"},
    {"name": "뷔", "group": "BTS"}
  ];

  final blackPink = people.where((x) => x["group"] == "블랙핑크").toList();
  
  print(blackPink);
}
<결과>
[{name: 로제, group: 블랙핑크}, {name: 지수, group: 블랙핑크}]

reduce

reduce의 처음만 prev에는 첫번째 값이 들어가고, next에는 다음 값이 들어간다.
그 다음부터 prev는 return한 값이 들어가고, 이전처럼 다음값이 들어간다.

void main() {
  List<int> numbers = [1, 3, 5, 7, 9];
  
  final result = numbers.reduce((prev, next){
    print("----------------");
    print("previous : $prev");
    print("next     : $next");
    print("total    : ${prev+next}");
    
    return prev+next;
  });
  
  print(result);
}
<결과>
----------------
previous : 1
next     : 3
total    : 4
----------------
previous : 4
next     : 5
total    : 9
----------------
previous : 9
next     : 7
total    : 16
----------------
previous : 16
next     : 9
total    : 25
25

위의 식은 아래처럼 줄일 수 있다.

final result = numbers.reduce((prev,next) => prev + next);

이렇게 단어를 이어서 문장을 만들 수도 있다.

void main() {
  List<int> numbers = [1, 3, 5, 7, 9];
  
  final result = numbers.reduce((prev, next){
    print("----------------");
    print("previous : $prev");
    print("next     : $next");
    print("total    : ${prev+next}");
    
    return prev+next;
  });
  
  List<String> words = ["안녕하세요", "저는", "코드팩토리입니다."];
  
  final sentence = words.reduce((prev,next) => prev + next);
  
  print(sentence);
}
<결과>
안녕하세요저는코드팩토리입니다.

여기서 주의할 점은 return 되는 값의 형태는 태초에 입력되는 값들, 위에서는 numbers면 int를, words면 String을 return해야 된다. 만약 다른 경우 오류가 발생하며, 이는 다른 방법으로 해결한다.

Fold

reduce에서 사용할 수 없던 다른 타입 반환이 가능한 방식
fold는 reduce와 달리 반환값이 정해진 것이 아니다. 그렇기에 어느 값을 반환할지에 대해 선언해주어야 한다. 이는 fold<반환형>으로 적어준다.
이때, 처음 prev에는 내가 처음 선언해준 값인 0이 들어가고 next에는 리스트의 첫번째 값인 1이 들어간다. 그리고 다음부터 prev에는 return한 값이 들어가고 next에는 3이 들어가는 방식이다.

void main() {
  List<int> numbers = [1,3,5,7,9];
  
  final sum = numbers.fold<int>(0,(prev,next)=>prev+next);
  
  print(sum);
}
<결과>
25

아무 형태나 리턴할 수 있는 장점이 있다. 이처럼 문자열로 된 리스트의 길이 값도 구할 수 있다.

void main() {
  List<String> words = ["안녕하세요","저는","코드팩토리","입니다."];
  
  final lengts = words.fold<int>(0,(prev,next) => prev + next.length);
  
  print(lengts);
}
<결과>
16

cascading operator

캐스케이딩 오퍼레이터는 ...을 사용하는데 리스트 안에다가 값을 풀어 넣는 역할을 한다.
이때, ...한 리스트는 기존의 리스트와는 다르다. 즉 number1과 ...number1은 다른 리스트이다.

void main() {
  List<int> number1 = [1,3,5,7,9];
  List<int> number2 = [2,4,6,8,10];
  
  print([number1,number2]);
  
  print([...number1,...number2]);
}
<결과>
[[1, 3, 5, 7, 9], [2, 4, 6, 8, 10]]
[1, 3, 5, 7, 9, 2, 4, 6, 8, 10]

실전

json형태로 들어온 데이터가 있다면 이를 클래스를 통해서 정형화해주는 것이 좋다. 왜냐하면 데이터가 들어오면서 오타가 있거나 다른 데이터가 있다면 이를 걸러줄 수 있어야 하기 때문. 그리고 클래스로 만들어두면 처리,제거 등 정해지기 때문에 데이터를 믿을수 있는 데이터가 된다.!!!

void main() {
  final List<Map<String, String>> people = [
    {"name": "지수", "group": "블랙핑크"},
    {"name": "로제", "group": "블랙핑크"},
    {"name": "뷔", "group": "BTS"},
    {"name": "RM", "group": "BTS"},
  ];

  final parsePeople =
      people.map((x) => Person(name: x["name"]!, group: x["group"]!)).toList();
  
  print(parsePeople);
}

class Person {
  final String name;
  final String group;

  Person({
    required this.name,
    required this.group,
  });
}
<결과>
[Instance of 'Person', Instance of 'Person', Instance of 'Person', Instance of 'Person']

위의 결과처럼 나오지 안게 하기 위해서는 기본적으로 제공되는 toString()를 사용한다.

class Person {
  final String name;
  final String group;

  Person({
    required this.name,
    required this.group,
  });
  
  @override
  String toString(){
    return "Person(name:$name), (group:$group)";
  }
}
<결과>
[Person(name:지수), (group:블랙핑크), Person(name:로제), (group:블랙핑크), Person(name:뷔), (group:BTS), Person(name:RM), (group:BTS)]
profile
아직 대학생입니다

0개의 댓글