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

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

Related

Flutter, when cleaning list that already got added to list, the values are gone

I need to sort the elements by their data.
For example:
When I have 4 entries and 2 of them have the same date, the result will be 3 entries in the result list
This is my code:
Future<List<List<MoodData>>> moodData() async {
var result = await database
.ref()
.child("users/")
.child(user!.uid)
.child("moodData")
.once();
List<MoodData> x = [];
List<List<MoodData>> resultdata = [];
result.snapshot.children.forEach((element) {
maxID = int.parse(element.key.toString());
print(element.child("date").value);
if (x.length != 2) {
x.add(MoodData(
id: int.parse(element.key.toString()),
date: element.child("date").value.toString(),
moodValue: double.parse(element.child("y_value").value.toString()),
text: element.child("text").value.toString()));
} else {
resultdata.add(x);
x.clear();
}
});
print(resultdata);
return resultdata;
}
The problem is, that in the result list, all the elemts are empty lists.
What is my code doing wrong?
When you adding x to resultdata it not produces the copy of x, x just becomes an element of resultdata.
Then you have 2 options for accessing x data:
Using given name x
Get it from resultdata by index
So when you call x.clear() after resultdata.add(x) it's the same as calling resultdata.last.clear().
The right solution is adding a copy of x([...x]) to resultdata:
resultdata.add([...x]);
x.clear();

Extract number and separate with comma from list in Flutter

List listFinal = [];
So listFinal have values from multiple list inside like below.
[["test: 111-333-5555", "test2: 222-333-4555"], ["test3: 555-333-2222"]]
How do I make this list so that it only extract numbers and separate with comma?
End result should be like
[1113335555, 2223334555, 5553332222]
I can think of trimming or regexp but not sure how to pull this off.
many thanks.
Try this
void main() {
List<String> numberList=[];
List<List<dynamic>> demoList=[["test: 111-333-5555", "test2: 222-333-4555"], ["test3: 555-333-2222"]];
for(int i=0;i<demoList.length;i++){
numberList.addAll(demoList[i].map((e) => e.toString().split(":")[1].replaceAll("-", "")).toList());
}
print(numberList.toString());
}
Here is an example to get you started. This doesn't handle things like malformed input strings. First step is to "flatten" the list with .expand, and then for each element of the flattened iterable use a regex to extract the substring. Other options might include using .substring to extract exactly the last 12 characters of the String.
You can see this in action on dartpad.
void main() {
final input = [
['test: 111-333-5555', 'test2: 222-333-4555'],
['test3: 555-333-2222']
];
final flattened = input.expand((e) => e); // un-nest the lists
// call extractNumber on each element of the flattened iterable,
// then collect to a list
final result = flattened.map(extractNumber).toList();
print(result);
}
final _numberRegExp = RegExp(r'.*: ([\d-]+)$');
int extractNumber(String description) {
var numberString = _numberRegExp.firstMatch(description).group(1);
return int.parse(numberString.replaceAll('-', ''));
}
Let's do this in a simple way.
List<List<String>> inputList = [
["test: 111-333-5555", "test2: 222-333-4555"],
["test3: 555-333-2222"]
];
List resultList = [];
print('Input List : $inputList');
inputList.forEach((subList){
subList.forEach((element){
var temp = element.split(' ')[1].replaceAll('-', '');
resultList.add(temp);
});
});
print('Output List : $resultList');
Here I have taken your list as inputList and stored the result in resultList.
For each element of inputList we get a sub-list. I have converted the elements of that sub-list into the needed format and added those into a List.
Happy Coding :)

Concatenating Future Lists in flutter

I am reading from 3 separate .json files via futures and want to concatenate them into one list. However, I dont't know how to, since .add and + seem to not be defined for future Lists. I also struggle to use then for further concatenation.
I want to return a Future with values from all 3 json files.
Code:
Future<List<Furniture>> getAllHousewares() {
if (_allHousewares != null) {
return _allHousewares;
}
_allHousewares = rootBundle.loadString("res/raw/housewares.json").then((json) =>
(jsonDecode(json) as List).map((houseware) => Furniture.fromJson(houseware)).toList());
_allWallmounteds = rootBundle.loadString("res/raw/Wall-mounted.json").then((json) =>
(jsonDecode(json) as List).map((wallmounted) => Furniture.fromJson(wallmounted)).toList());
_allMiscellaneouss = rootBundle.loadString("res/raw/miscellaneous.json").then((json) =>
(jsonDecode(json) as List).map((miscellaneous) => Furniture.fromJson(miscellaneous)).toList());
return _allHousewares;
}
For this case, the best way to handle it is to use the wait static method of the Future class. The method:
Waits for multiple futures to complete and collects their results.
Since all of your loaded JSON strings contain the same datatype, you can handle them all the same way with loops which leads to cleaner code. This code uses await, which is just syntactic sugar for .then.
After the data for each json is processed, it's concatenated with expand, though it could have been easily done with the + operator as well.
Example:
Future<List<Furniture>> getAllHousewares() async {
if (_allHousewares != null) {
return _allHousewares;
}
Future _allHousewares = rootBundle.loadString("res/raw/housewares.json");
Future _allWallmounteds = rootBundle.loadString("res/raw/Wall-mounted.json");
Future _allMiscellaneouss = rootBundle.loadString("res/raw/miscellaneous.json");
List combined = await Future.wait([_allHousewares, _allWallmounteds, _allMiscellaneouss ]);
List<List<Furniture>> tempFurniture= List();
for(String json in combined) {
tempFurniture.add((jsonDecode(json) as List).map((thingInList) => Furniture.fromJson(thingInList)).toList());
}
List<Furniture> furniture = tempFurniture.expand((item) => item).toList();
return furniture;
}

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

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!

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'];
}