Reputation: 1537
I have this list of maps.
[
{title: 'Avengers', release_date: '10/01/2019'},
{title: 'Creed', release_date: '10/01/2019'}
{title: 'Jumanji', release_date: '30/10/2019'},
]
I would like to write a code that would group the list of movies by release_date
like that.
[
{
"10/01/2019": [
{
"title": "Avengers"
},
{
"title": "Creed"
}
]
},
{
"30/10/2019": [
{
"title": "Jumanji"
}
]
}
]
Upvotes: 64
Views: 88570
Reputation: 18923
The package collection implements
the groupBy
function.
For grouping by date:
import "package:collection/collection.dart";
main(List<String> args) {
var data = [
{"title": 'Avengers', "release_date": '10/01/2019'},
{"title": 'Creed', "release_date": '10/01/2019'},
{"title": 'Jumanji', "release_date": '30/10/2019'},
];
var newMap = groupBy(data, (Map obj) => obj['release_date']);
print(newMap);
}
For removing the release_date
key from each map entry:
var newMap = groupBy(data, (Map obj) => obj['release_date']).map(
(k, v) => MapEntry(k, v.map((item) { item.remove('release_date'); return item;}).toList()));
For changing a key:
var newMap = groupBy(data, (Map obj) => obj['release_date']).map(
(k, v) => MapEntry(k, v.map((item) => {'name': item['title']}).toList()));
Upvotes: 124
Reputation: 712
I don't know why no one has mentioned that with how basic built-in functions and methods you can achieve it, like:
main() {
List<Map> data = [
{'title': 'Avengers', 'release_date': '10/01/2019'},
{'title': 'Creed', 'release_date': '10/01/2019'},
{'title': 'Jumanji', 'release_date': '30/10/2019'},
];
// Loop through empty {} map and check if the release date exists, if not
// add as the key and empty list as the value, then fill the list with element
// itself, removing 'release_date' before adding. Then you can map the map
// to a list of maps.
List result = data
.fold({}, (previousValue, element) {
Map val = previousValue as Map;
String date = element['release_date'];
if (!val.containsKey(date)) {
val[date] = [];
}
element.remove('release_date');
val[date]?.add(element);
return val;
})
.entries
.map((e) => {e.key: e.value})
.toList();
print(result);
}
Output:
C:\Users\duoqu\Desktop>dart run test.dart
[{10/01/2019: [{title: Avengers}, {title: Creed}]}, {30/10/2019: [{title: Jumanji}]}]
Upvotes: 7
Reputation: 2966
extension UtilListExtension on List{
groupBy(String key) {
try {
List<Map<String, dynamic>> result = [];
List<String> keys = [];
this.forEach((f) => keys.add(f[key]));
[...keys.toSet()].forEach((k) {
List data = [...this.where((e) => e[key] == k)];
result.add({k: data});
});
return result;
} catch (e, s) {
printCatchNReport(e, s);
return this;
}
}
}
then use it like this
var data = [
{"title": 'Avengers', "release_date": '10/01/2019'},
{"title": 'Creed', "release_date": '10/01/2019'},
{"title": 'Jumanji', "release_date": '30/10/2019'},
];
var result = data.groupBy('title');
print(result);
then the result is
[{10/01/2019: [{title: Avengers, release_date: 10/01/2019}, {title: Creed, release_date: 10/01/2019}]}, {30/10/2019: [{title: Jumanji, release_date: 30/10/2019}]}]
Upvotes: 4
Reputation: 111
To add to the accepted answer if you come arcross this, In flutter 2, you will Get an error, as i got.
The operator '[]' isn't defined for the type 'dynamic Function(dynamic)'
Use
var data = [
{"title": 'Avengers', "release_date": '10/01/2019'},
{"title": 'Creed', "release_date": '10/01/2019'},
{"title": 'Jumanji', "release_date": '30/10/2019'},
];
var newMap = groupBy(data, (Map oj) => oj['release_date']);
print(newMap);
This might be of help to someone.
Upvotes: 4
Reputation: 35997
Using the supercharged package, you'd write it like this:
List list = [
{ title: 'Avengers', release_date: '10/01/2019' },
{ title: 'Creed', release_date: '10/01/2019' }
{ title: 'Jumanji', release_date: '30/10/2019' },
];
final map = list.groupBy<String, Map>((item) =>
item['release_date'],
valueTransform: (item) => item..remove('release_date'),
);
Upvotes: 2
Reputation: 3998
If you have Dart 2.7, you can extend Iterable
to add a useful groupBy
method:
extension Iterables<E> on Iterable<E> {
Map<K, List<E>> groupBy<K>(K Function(E) keyFunction) => fold(
<K, List<E>>{},
(Map<K, List<E>> map, E element) =>
map..putIfAbsent(keyFunction(element), () => <E>[]).add(element));
}
Now, you're List of Maps, could be grouped using something like:
final releaseDateMap = listOfMaps.groupBy((m) => m['release_date'])
Data like this:
[
{title: 'Avengers', release_date: '10/01/2019'},
{title: 'Creed', release_date: '10/01/2019'}
{title: 'Jumanji', release_date: '30/10/2019'},
]
would turn into:
{
'10/01/2019': [
{title: 'Avengers', release_date: '10/01/2019'},
{title: 'Creed', release_date: '10/01/2019'}
],
'30/10/2019': [
{title: 'Jumanji', release_date: '30/10/2019'},
]
}
Upvotes: 76
Reputation: 9545
This is a method naively implemented (in case you don't want to use the groupBy function from the collections package):
List<Map<String, List<Map<String, String>>>> MapByKey(String keyName, String newKeyName, String keyForNewName, List<Map<String,String>> input) {
Map<String, Map<String, List<Map<String, String>>>> returnValue = Map<String, Map<String, List<Map<String, String>>>>();
for (var currMap in input) {
if (currMap.containsKey(keyName)) {
var currKeyValue = currMap[keyName];
var currKeyValueForNewName = currMap[keyForNewName];
if (!returnValue.containsKey(currKeyValue)){
returnValue[currKeyValue] = {currKeyValue : List<Map<String, String>>()};
}
returnValue[currKeyValue][currKeyValue].add({newKeyName : currKeyValueForNewName});
}
}
return returnValue.values.toList();
}
void main() {
var test = [
{"title": 'Avengers', "release_date": '10/01/2019'},
{"title": 'Creed', "release_date": '10/01/2019'},
{"title": 'Jumanji', "release_date": '30/10/2019'},
];
var testMapped = MapByKey("release_date", "name", "title", test);
print("$testMapped");
}
The output is:
[
{
10/01/2019: [
{name: Avengers
},
{name: Creed
}
]
},
{
30/10/2019: [
{name: Jumanji
}
]
}
]
Upvotes: 3
Reputation: 1897
It may not be the best solution. But it can give you an idea
List arrayData = [
{"name": 'John', "gender": 'male'},
{"name": 'James', "gender": 'male'},
{"name": 'Mary', "gender": 'female'}
];
Retrieve list by gender:
List males = arrayData.where((o) => o['gender'] == "male").toList();
List females = arrayData.where((o) => o['gender'] == "female").toList();
Make new map with desired format:
List result = [
{
"male": males.map((f) => {"name": f['name']}).toList()
},
{
"female": females.map((f) => {"name": f['name']}).toList()
}
];
print:
debugPrint('${result}');
result:
[{male: [{name: John}, {name: James}]}, {female: [{name: Mary}]}]
Upvotes: -1