How to retrieve a Map from a Map in dart efficiently? - flutter

I have a map returned from json.decode of type Map<String,dynamic>
The dynamic part contains another map which I want to have in a separate variable. I managed to do that in the following way:
Map<DateTime, List<DayOffDto>> mapToReturn = Map();
Map<String, dynamic> responseBody = json.decode(
response.body,
reviver: _reviver,
);
if (responseBody == null) {
throw NoDataServerException();
}
responseBody.entries.forEach((element) {
Map map = element.value;
//map.values;
map.entries.forEach((element2) {
mapToReturn[element2.key] = element2.value;
});
});
//mapToReturn contains now the extracted map from responseBody
and the reviver function just does some converting for me
_reviver(dynamic key, dynamic value) {
if (key != null && value is Map && (key as String).contains("-")) {
var object = value;
final DayOffDto dayOffDto = DayOffDto.fromFirebase(
key_firebase: key as String,
parsedJson: value,
rota: rotaParam,
chosenYear: yearParam);
DateTime datetime = Helper.getDateTimeFromDayNumber(
dayOffDto.dayNumber,
dayOffDto.year,
);
Map<DateTime, List<DayOffDto>> internalMap = LinkedHashMap();
internalMap[datetime] = [dayOffDto];
return internalMap;
}
return value;}
I do not think it is the best way of extracting . Any idea for the optimized code?
responseBody.values returns Iterable<V>
so when I do
mapToReturn = responseBody.values i am getting an error

Working with Map can be hard sometimes. I would like to tell you that there is something as easy as mapToReturn = responseBody.values, but as of today, there is not (that I could find).
However, I can give you one small block of code that does the same as your first code block.
As you are not using the keys of your first map, instead of responseBody.entries you should use responseBody.values. So the code block would end up like this:
responseBody.values.forEach((value) {
return value is Map<DateTime, List<DayOffDto>>
? mapToReturn.addAll(value)
: null;
});
And if you are completely sure about the value Type (you should, as you are using a reviver) you can make it only one line of code.
responseBody.values.forEach((value) => mapToReturn.addAll(value));
I hope this can help you!

Related

Dart/Flutter: How can i calculate values of multiple maps which contains same key?

I am new to Dart and i got stuck at this point for days.
I have multiple maps and these maps follow the same pattern (date:value) but their lengths are different. And these maps are increased dynamically.
For example:
Map1:{01.01.2021:2,02.01.2021:5,03.01.2021:3},
Map2:{02.01.2021:10,03.01.2021:4,04.01.2021:8},
Map3...
Map4...
...
I want to combine these maps and sum the values that contains the same key and store it in an another map. For the different keys, there will be no calculation and store as it is.
Result for Map1 & Map2:
Combined Map{01.01.2021:2,02.01.2021:(5+3),03.01.2021:(3+4),04.01.2021:8}
How can i perform such an operation considering that these maps are iterable inside a class or inside an another list.
Thank you in advance.
Here you go! Paste this on DartPad
This will work with any number of maps inside data map
Any questions fell free to ask me in the comments.
void main() {
final data = {
'Map1': {'01.01.2021':2,'02.01.2021':5,'03.01.2021':3},
'Map2': {'02.01.2021':10,'03.01.2021':4,'04.01.2021':8},
};
final finalData = {};
for(final key in data.keys) {
for(final date in data[key]!.keys) {
final initialValue = finalData[date];
if(initialValue == null) {
finalData[date] = data[key]![date];
} else {
finalData[date] = initialValue + data[key]![date];
}
}
}
// {01.01.2021: 2, 02.01.2021: 15, 03.01.2021: 7, 04.01.2021: 8}
print(finalData);
}
The inner loop can be written more succinctly using the tertiary operator
for (final date in data[key]!.keys) {
final initialValue = finalData[date];
finalData[date] = initialValue == null
? data[key]![date]
: initialValue + data[key]![date];
}
or the null aware operator (??)
for (final date in data[key]!.keys) {
finalData[date] = data[key]![date]! + (finalData[date] ?? 0);
}

Filter list with whereIn condition in Flutter?

This code sample works fine.
var box = await Hive.openBox<MainWords>('mainWords');
box.values.where((item) {
return item.category == "6" || item.category == '13';
}).toList();
I am trying to filter a list with whereIn condition but it must filter like
List<String> categoryList = ['6', '13'];
var box = await Hive.openBox<MainWords>('mainWords');
box.values.where((item) {
return item in categoryList; // just an examle
}).toList();
How can i achive this?
You should not use the keyword in but the method contains to check if your item exists inside categoryList. Moreover you cannot compare values of different types, I'm seeing that you are returning with box.values an Iterable<MainWords>.
I don't know the content of this class but the item variable is of type MainWords and so it cannot be compared with a String object directly.
I am supposing that you have some access to a String value from your class MainWords so you will need to compare this value with your list.
Code Sample
List<String> categoryList = ['6', '13'];
var box = await Hive.openBox<MainWords>('mainWords');
// As I don't know what are MainWords' properties I named it stringValue.
box.values.where((item) => categoryList.contains(item.stringValue)).toList();

Dart / Flutter : Waiting for a loop to be completed before continuing... (Async Await?)

I have a function which creates a sublist from a large(very large list). After creating this list, the function goes on treating it (deleting duplicates, sorting...).
As long as the list was not too big, it worked fine. But now, I get "The Getter length was called on null". I suppose, it's because the second part of the function (after the loop) starts before the sublist is completed... so it doesn't work...
How can we force the function to wait for the loop to be over to continue the rest of the treatment ?
Is it with Async /Await ? Or can we do something like "While... something is not over...", or "As soon as something is done... do that" ? (My suggestions might be naive, but I am a beginner...)
Here is the code :
List themeBankFr() {
List<Map> themeBankFr = [];
for (Word word in wordBank) {
for (Thematique wordTheme in word.theme) {
themeBankFr.add({
'themeFr': wordTheme.themeFr,
'image': wordTheme.image,
});
}
}
// convert each item to a string by using JSON encoding
final jsonList = themeBankFr.map((item) => jsonEncode(item)).toList();
// using toSet - toList strategy
final uniqueJsonList = jsonList.toSet().toList();
// convert each item back to the original form using JSON decoding
final result = uniqueJsonList.map((item) => jsonDecode(item)).toList();
// sort the list of map in alphabetical order
result.sort((m1, m2) {
var r = m1['themeFr'].compareTo(m2['themeFr']);
if (r != 0) return r;
return m1['image'].compareTo(m2['image']);
});
return result;
}
i think i have a good answer that may helps you and it will as following
first create another function to do the work of for loops and this function returns a future of list that you need like below
Future<List<Map>> futureList(List wordBank){
List<Map> themeBankFr = [];
for (Word word in wordBank) {
for (Thematique wordTheme in word.theme) {
themeBankFr.add({
'themeFr': wordTheme.themeFr,
'image': wordTheme.image,
});
}
}
return Future.value(themeBankFr);
}
after that you can use this function inside your code and use it as async await and now you will never run the below lines before you return this array like below
List themeBankFr() async {
List<Map> themeBankFr = await futureList(wordBank);
// convert each item to a string by using JSON encoding
final jsonList = themeBankFr.map((item) => jsonEncode(item)).toList();
// using toSet - toList strategy
final uniqueJsonList = jsonList.toSet().toList();
// convert each item back to the original form using JSON decoding
final result = uniqueJsonList.map((item) => jsonDecode(item)).toList();
// sort the list of map in alphabetical order
result.sort((m1, m2) {
var r = m1['themeFr'].compareTo(m2['themeFr']);
if (r != 0) return r;
return m1['image'].compareTo(m2['image']);
});
return result;
}
i think this will solve your problem and i hope this useful for you

Map<string, string> argument

I'm trying to assign a Map<string, string> argument to double. If that's even what I have to do. I have no idea how to work with this argument type. Here it is:
await sheet.values.map.column(3)
I'm using this to extract column #3 and all its values from a google sheet via gsheets. This is a nightmare to work with... Anybody know if there's another way to call the column? or if there's a way to convert the Map<string, string> to a single string containing only the values in the column ? In this case, they're coordinate values for longitude or latitude. I'm trying to call these values for plotting in Google maps. Here's the rest of my code:
Iterable markers = [];
var latstr = (sheet.values.map.column(3)); //latitude
var lngstr = (sheet.values.map.column(4)); //longitude
List<dynamic> names = [];
List<double> lat = [];
List<double> lng = [];
for (var i = 0; i < 10; i++) {
names.add(latstr);
lat.add(parse(await sheet.values.map.column(3)); //<--- I have no idea what I'm doing here. Trying to convert to double. very confused.
lng.add(await sheet.values.map.column(4));
}
to add to this, here's the full error:
The argument type 'Map<String, String>' can't be assigned to the
parameter type'double'.
here's how i'm pulling from google sheets:
const _spreadsheetId = 'xxxxxxxxxxxxxx';
final gsheets = GSheets(_credentials);
final ss = await gsheets.spreadsheet(_spreadsheetId);
var sheet = await ss.worksheetByTitle('xxxxxxxxxxxx');
As the document says await sheet.values.map.column(4) gives you a Map<String,String>, but lng is List<double>, so only doubles can be added to it but you are trying to asign a Map<String,String> which results in the error,
//try this to map the map into a map of doubles (mapception), if your okey with using Map instead of a list
Map<double,double> m = (await sheet.values.map.column(4)).map((key, value)=> MapEntry(double.parse(key), double.parse(value)));
parse will throw if it encounters a character which is not a digit

Flutter - Map not working when addAll function call

This the code I have right now (I'm using Mobx):
#observable
ObservableMap dates = ObservableMap();
#action
void getDate() {
final Map obj = {};
final map = item['dates'].map((date) {
DateTime key = DateTime.parse(date['date']);
obj.addAll({
key: ['list']
});
});
// print(map);
dates.addAll(obj);
}
I have function to call query and call getDate function.
At my UI I just call the dates but it won't return any value. The value only return if the print syntax not comment.
Any solutionn?
You are using the map method to do something for each element of item['dates']. That doesn't work because the map operation is lazy and doesn't do anything until you start using the result. You can call .toList() on the result to make it do all the computations, but that's a roundabout way to do it.
Use forEach instead to eagerly do something for each element, or, even better, use a for-in loop:
item['dates'].forEach((date) { ... });
or
for (var date in item['dates']) {
var key = DateTime.parse(date['date']);
obj.addAll({key: ['list']});
// or just:
// obj[key] = ['list'];
}