I am writing some code where I have a list that gets added to alot. Each time it gets added it has 2 values: a string and an integer. I would like that it takes all of that data and that it gets the average of the integer per string, and puts that in a list.
Example:
void main() {
List people = [];
people.add({'person': 'mike', 'score': 32});
people.add({'person': 'david', 'score': 29});
people.add({'person': 'mike', 'score': 28});
people.add({'person': 'kim', 'score': 34});
people.add({'person': 'david', 'score': 31});
people.add({'person': 'david', 'score': 31});
people.add({'person': 'kim', 'score': 32});
print(people);
}
Above you can see the list people has a few different persons and scores. I would like it that when I print(people) it shows a list like:
{['person': 'mike', 'score': 30], ['person': 'david', 'score': 30], ['person': 'kim', 'score': 33]}
As you can see above the scores are the average lists of the full list, and doubles get rounded to ints.
Is there a way to do this?
It requires some mapping. First collect all scores per person in a Map. Then recreate the entries in the desired format. This can be done a bit more compact but I think this makes it easier to read.
Note that this implementation returns a double
as the score instead of an int
. If that's not desired, you can add a .round()
to the calculation of the average. Or as Tray Denney suggested, use the ~/
operator which divides and returns an int by ignoring the decimals.
void main() {
List people = [];
people.add({'person': 'mike', 'score': 32});
people.add({'person': 'david', 'score': 29});
people.add({'person': 'mike', 'score': 28});
people.add({'person': 'kim', 'score': 34});
people.add({'person': 'david', 'score': 31});
people.add({'person': 'david', 'score': 31});
people.add({'person': 'kim', 'score': 32});
final scoresPerPerson = people.fold<Map<String, List<int>>>(
{}, // initial empty map
(map, person) {
final name = person['person'];
map.update(
name,
(scores) => [...scores, person['score']], // update the existing list of scores
ifAbsent: () => [person['score']], // create a new list of scores for this person
);
return map;
},
);
final averages =
scoresPerPerson.entries.map((MapEntry<String, List<int>> item) {
return {
'person': item.key,
'score': item.value.reduce((a, b) => a + b) /
item.value.length, // calculate the average of all scores
};
});
print(averages);
}