New to Dart (Flutter), and the docs don't seem to have a method for the Map class that will allow me to do this easily...
I want to have a Map with keys of Datetime and values of calories eaten.
{'2019-07xxx': 350, '2019-07xxx': 500, ...}
Now, what's the best way to filter this so that I only get values from today? (i.e. when starting the app and pulling the data from storage)
Ideally once I do that, I can get the cumulative value of today's calories so far with:
var sum = todaysCaloriesArray.reduce((a, b) => a + b);
Unless there is some Dart-fu that would allow this in a better way?
You could use .where on the map's entries. For example:
var map = Map<String, int>();
var sum = map.entries
.where((e) => e.key.startsWith('2019-07-22'))
.map<int>((e) => e.value)
.reduce((a, b) => a + b);
The first answer was great! But you can use the fold method so you can use in empty collections.
var map = Map<String, int>();
var sum = map.entries
.where((e) => e.key.startsWith('2019-07-22'))
.fold(0,(int a, b) => a + b.value);
Related
I have a map with String,double and I want to sort this map based on its value and want to take only first 4 key value pair..like following
Map<String,dynamic> mymap={
'A':2000,
'B':8000,
'C':300,
'D':3890,
'E':8030,
'F':300,
'G':900,
};
and I want to convert into following
Map<String,dynamic> resultmap={
'E':8030,
'B':8000,
'D':3890,
'A':2000,
'Others':1500,
};
To sort a map in descending order by value, you can use something like below (look here for more info).
var numbers = {'one': 1, 'two': 2, 'three': 3, 'four': 4};
print(numbers); // {one: 1, two: 2, three: 3, four: 4}
final sortedValuesDesc = SplayTreeMap<String, dynamic>.from(
numbers, (keys1, keys2) => numbers[keys2]!.compareTo(numbers[keys1]!));
print(sortedValuesDesc); // {four: 4, three: 3, two: 2, one: 1}
To get the sum of the rest of the values, there are some different options to choose from. I found this approach here on Stack Overflow:
final sum = numbers
.values
.skip(4)
.reduce((value, element) => value + element);
What remains is to make sure the summed elements are removed and the above sum is added to the map along with your desired key.
Let me know if this worked for you. :-)
You can do this in several steps.
First declare your map.
Map<String,dynamic> mymap={
'A':2000,
'B':8000,
'C':300,
'D':3890,
'E':8030,
'F':300,
'G':900,
};
Then, sorting the declared map in descending order by using this code.
var sortedList = mymap.entries.toList()..sort((b,a)=>a.value.compareTo(b.value));
Then, create a new map and add the sorted list as entries inside the new map.
Map newMap={};
newMap.addEntries(mapList);
Now, find other number's sum using this code.
int otherNumbersSum = newMap.values.skip(4).reduce((value, element) => value + element);
Finally, create a new map and add entries in that map by checking that either they are three digits or four digits and at last adding the sum which we got in the last step.
Map finalMap ={};
for(var a in newMap.entries){
if(a.value>999){
finalMap[a.key] = a.value;
}
}
finalMap["Others"] = otherNumbersSum;
You will get result like this.
finalMap ={
'E':8030,
'B':8000,
'D':3890,
'A':2000,
'Others':1500,
};
Hope it will help :)
I've got a list of object which after looping I'm trying to sort the final list by given ISO8601 format favouriteDateTime: 2022-12-16T10:46:55.551Z. There are mutiple sorting method but which one to use and how to sort it.
List<Movies> get Movies{
List<Movies> favMoviesList = <Movies>[];
for (final category in _appData.categories) {
for (final series in category.series!) {
final favMovies = series.movie!
.where((movie) =>
movie.stats != null && movie.stats!.isFavourite == true)
.toList();
if (favMovies.length > 0) {
List<Movies> sorted = favMovies
..sort((a, b) => b.stats!.favoriteDateTime!
.compareTo(a.stats!.favoriteDateTime!));
favMoviesList.addAll(sorted);
}}}
return favMoviesList;
}
Looks like you've already got a working implementation here. ISO8601 timestamps can just be sorted with string comparison - for two ISO strings a and b, a > b will always be true if time a is after time b, and the inverse is also true.
As far as the actual sorting method goes, you've got the right idea here with using sort(). Just make sure you only have one period -- favMovies.sort(), not favMovies..sort().
Also, List.sort() does not return the sorted list, it sorts the list in place. So your sorting code should be:
favMovies.sort((a, b) =>
b.stats!.favoriteDateTime!.compareTo(a.stats!.favoriteDateTime!)
);
favMoviesList.addAll(favMovies);
I am asking for help because I don't know how to solve this issue.
I am currently mapping on an Array of object with this code to output an array of string :
contexts = snapshot.data!.myContexts
.where(
(e) => e.organisation.name == organizationValue)
.map((e) => e.projects.map((e) => e.name)).toList();
The last .toList make the difference in the output value from getting an array of list [()] and a list of list (()).
I wanted to know How I could get only a list of string or an array of string.
Thank you in advance, Weac
Can you try creating the list this way ?
final organization = snapshot.data!.myContexts
.firstWhere(
(e) => e.organisation.name == organizationValue);
contexts = List<String>.generate(organization.projects.length,(index)=>organization.projects[index].name);
Assuming the organization is always unique and you can't have two organization with the same name.
Currently, I am fetching a list of video files present in the directory using the following code
var videoList = _videoDir
.listSync()
.map((item) => item.path)
.where((item) => item.endsWith(".mp4"))
.toList(growable: true);
This generates a video list in random order. How can I fetch files in order of latest to oldest?
Update
I already tried to use the startsync() function at the end of the code but it cant be used on the type String when used after .toList()
Use stat() or statSync() function of File class to sort the list in desired order.
var videoList = videoDir.listSync()
.where((e) => e.path.endsWith('.mp4'))
.toList()
..sort((l, r) => l.statSync().modified.compareTo(r.statSync().modified));
var videosPathList = videoList.map((e) => e.path).toList();
Note
List is growable by default.
List<FileSystemEntity> toList({bool growable = true})
dart:core
Creates a [List] containing the elements of this [Iterable].
The elements are in iteration order. The list is fixed-length if [growable] is false.
APIs:
FileStat
File class
I have a list of strings, when I click a button I want to generate a new list with a specific number of items from my original list of strings.
I'm able to generate a random list with no repeating items but the number of items that returns is random. For example I want a new list of 5 items, sometimes it returns with 2 items other times 4 etc.
var randomList = new List.generate(
5, (_) => originalList[Random().nextInt(originalList.length)]).toSet().toList();
I've found lots of info for returning 1 random item, but nothing about multiples.
EDIT:
Thank you everyone for the responses, I was able to fix my problem by using shuffle like so
var randomList = (originalList..shuffle()).take(5).toList();
Your method of getting random items out of the original list will result in duplicates, which are then eliminated when you call .toSet(), which is why you get lists of varying lengths.
Instead of calling .toSet() to prevent duplicates, we need to be sure that no duplicates are chosen in the first place.
One way of doing that would be to generate a list of numbers from 0 up to originalList.length - 1, then shuffle them, and then choose the first n numbers from that list, and map them to values from original list.
void main() {
List<String> originalList = ["hello", "what", "goodbye", "Test", "Apple", "Banana"];
List<int> indices = List<int>.generate(originalList.length, (i) => i);
indices.shuffle();
int newCount = 3;
List<String> randomList = indices.take(newCount).map((i) => originalList[i]).toList();
print(randomList);
}
This method is efficient, and has a worst case performance of O(n), assuming dart has an efficient shuffle() implementation (which I'm sure it does).
The problem here is the list generates duplicates nonetheless.
var randomList = new List.generate(5, (_) => originalList[Random().nextInt(originalList.length)])
The list could contain [dello, kello, hello, gello, hello]
(for example, assume items are taken from the original list)
Now performing .toSet() on this will remove the duplicate hello from the list, this is what causes the list size to be random. In this instance it's two duplicates, but later on it could have more.
A simple solution for this would be
var randomList = [];
List.generate(5, (_) {
var randomString = originalList[Random().nextInt(originalList.length)];
while (randomList.contains(randomString)) {
randomString = originalList[Random().nextInt(originalList.length)];
}
randomList.add(randomString);
});