일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 플러터 #안드로이드 #플레이콘솔 #앱내리기
- flutter #dart #stream
- 희망적금연계
- 안드로이드 #코틀린 #코루틴 #콜백 #채널
- 희망적금전환
- 도약연계
- 도약전환
- 청년도약계좌환승
- Flutter #Stream #dart
- 조립 후 재부팅
- Flutter #Stream
- 도약계좌전환
- Today
- Total
Flutter 개발 상자
[Flutter] 문화충격을 받은 GroupBy 함수 사용법 본문
문제
문제 드립니다.
플러터에서 아래와 같은 데이터 클래스가 있습니다.
class Event {
String name;
DateTime date;
}
위 데이터가 여러개 있는 List<Event> 를 (1,2,3,..)월별로 리스트를 묶고 그 리스트를 1월부터 순차적으로 출력해보세요.
생각보다 쉽지 않은 이유
월별로 데이터를 묶어야 하기때문에 List<Event> 가 여러개가 있는 형태가 되어야 합니다.
그렇다면
List<List<Event>>
Map<int, List<Event>>
의 형태를 기본적으로 생각하게 되겠네요.
근데 각각의 형태는 문제점이 있습니다.
일단 첫번째 List 데이터의 경우 월에 대한 데이터 정보가 없습니다.
1월부터 12월까지 데이터가 꽉차있다면 인덱스로 접근할 수 있지만 중간에 비어있는 월이 있다면 인덱스로 접근하는건 위험합니다.
결국 아이템에 접근해서 월을 파악해야하는데 결코 깔끔한 방법이 아니죠
두번째 Map의 경우 월별 데이터를 직관적으로 파악할 수 있어서 좋습니다.
하지만 문제의 마지막에서는 '순차적 출력' 이라는 문장이 있습니다.
Map은 순서가 보장되지 않기때문에 순차적 출력을 위해서는 결국 키값을 비교하여 정렬을 해줘야하는 문제가 있습니다.
저 또한 위의 시행착오를 겪고나서 Dart 3.0 문법을 통해서 해결해야겠다는 생각을 하게 되었습니다.
List<({int month, List<Event> list})>
위와같은 (int, List<Event>) 타입을 만들어서 이것을 리스트로 만들고 데이터를 넣을때 순차적으로 집어 넣도록 하는것입니다.
이러면 데이터를 받아서 사용하는 Widget단에서 순차적으로 데이터를 출력하는데 문제가 없고, 이 리스트 데이터가 몇월의 리스트인지도 알기 쉽습니다.
자, 근데 또하나의 문제가 남아있습니다.
무작위로 나열된 저 리스트를 어떻게 또 저 타입으로 그룹핑해줘야할까요?
일단 데이터를 순차적으로 넣어야하기때문에 리스트가 정렬이 되어있어야 할 것 같습니다.
정렬을 하지 않는다면 모든 월에 대한 리스트를 미리 생성해둔다음 아이템을 순회하면서 이 아이템을 해당 월에 맞는 리스트안에 넣는 방법도 있겠네요.
저는 여러가지 방법을 혼합하여 실제로 저 그룹핑리스트를 만드는데 성공했지만 코드가 꽤나 복잡하고 지저분했습니다.
그래서 혹시나 하는 마음으로 AI에게 좀 더 간결한 코드가 가능한지를 물어봤고 그 대답으로 나온게 'GroupBy' 함수입니다.
GroupBy 함수 사용법
GroupBy 함수는 collection 라이브러리의 함수입니다.
collection 라이브러리는 그냥 프로젝트 생성하면 바로 디펜더시에 추가하는게 좋습니다. 유용한게 많거든요
디펜더시에 추가하지 않아도 import는 가능하던데 정확한 이유는 잘 모르겠습니다. 아시는분은 제보해주세요.
1. 기본 사용법
// 기본 사용 예시
Map<키타입, List<원소타입>> groupedMap = list.groupBy((item) => 그룹화할키);
final numbers = [1, 2, 3, 4, 5, 6];
final groupedNumbers = numbers.groupBy((n) => n % 2 == 0 ? 'even' : 'odd');
// 결과: {'odd': [1, 3, 5], 'even': [2, 4, 6]}
숫자를 짝수와 홀수로 나누어 맵 형태로 출력했습니다.
위 함수는 기본적으로 Map타입을 반환해주며 groupBy 내부에서 키값을 리턴하도록 되어있는데 이 리턴받은 키값에 해당 Element값이 그룹핑되는 형식으로 보입니다.
class Person {
String name;
int age;
Person(this.name, this.age);
}
final people = [
Person('Alice', 25),
Person('Bob', 30),
Person('Charlie', 25)
];
final groupedByAge = people.groupBy((p) => p.age);
// 결과: {
// 25: [Person('Alice', 25), Person('Charlie', 25)],
// 30: [Person('Bob', 30)]
// }
좀 더 응용된 형태입니다. 객체에있는 age를 키값으로 리턴을 했더니 age 별로 그룹핑이 되었습니다.
기본사용법만 봤을때는 흠... 싶었는데 응용 사용법을 보니 와 이건 좀 유용하겠는데? 생각이 바로 듭니다.
이번에는 처음 문제를 해결해보겠습니다.
List<({int month, List<Event> list})> groupByMonth(List<Event> originList) {
return groupBy((event) => event.date.month).entries.map((entry) => (
month: entry.key,
list: entry.value
)).toList();
}
네. 계산하는 코드가 단 4줄에 새로운 변수 생성 if문, for문 하나도 없습니다.
date의 월 데이터를 리턴값으로 사용해서 월별로 데이터를 묶어서 map을 만들고 그대로 체인메서드로 entries를 겁니다. 이건 Map의 전체 데이터를 iterator 형태로 받아오는겁니다. 다시 체인메서드로 map을 겁니다.
다들 아시겠지만 자료구조 Map과 다른겁니다. 리스트를 순회하면서 데이터를 변형하여 새로운타입의 리스트를 만들때 쓰이죠. 이 Map을 이용하여 애초에 원했던 타입으로 변형까지 완료했습니다.
근데 이 코드도 사실 문제가 있습니다. 결국 Map으로 변환한걸 다시 List로 만든거라 순서가 보장이 되지 않습니다.
결국 Sort하는 과정은 한번 넣어야하네요.
이 Sort 하는 과정을 GroupBy 함수 내부에 어떻게 또 구현할 수 있지 않을까 했지만 기본적으로 Map을 출력해주는 함수라서 그런건 없었습니다.
결국 성능까지 챙기려면 처음 냈던 문제의 해답은 GroupBy가 아니라 미리 비어있는 월별 리스트를 다 만들어놓고 리스트를 한번 순회하면서 각각에 맞는 월별 리스트에 데이터를 집어넣는게 가장 현명할 것 같습니다. 이러면 뭐 for문을 딱 한번 돌기때문에 성능은 문제없죠
다만 작은크기의 데이터라면 GroupBy 함수를 이용하는것도 좋을것같습니다.
무튼 유용한 함수를 이제야 깨달았네요.
'Flutter > 간단팁' 카테고리의 다른 글
[Flutter] flutter_quill_extensions hide video button 비디오 버튼 숨기기 (1) | 2025.02.08 |
---|---|
[Flutter] FVM 삭제 완료 (0) | 2025.02.05 |
[Flutter] 처음알았다. key.properties의 storeFile 경로 설정에 대하여 (1) | 2024.12.11 |
[Flutter] FVM을 brew로 설치하기 (1) | 2024.12.05 |
[Flutter] 안드로이드 스튜디오에서 Xcode 실행하기 (3) | 2024.08.05 |