Dart program execution is not in order - flutter

In my program I use 2 large json files locally.
My program works, but when I increase the size of the jsons the order of the prints in the console does not arrive any more in the order and seem to be mixed at the end.
How can we be sure that everything is executed correctly?
...
children: <Widget>[
_buildDistance(),
_buildAltitudePosition(),
_buildAltitudeObjectif(),
SizedBox(height: 100),
RaisedButton(
child: Text(
'Calculer',
style: TextStyle(color: Colors.blue, fontSize: 16),
),
onPressed: () {
if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();
userDifferenceAltitude = userAltitudeObjectif - userAltitudePosition;
// Function which searches for all the charges which correspond to my distance and classifies them in the order of height
// Return a load map list
List searchCharges(int userDistance) {
var result = <Map<String, dynamic>>[];
// Create a list with the load which is the distance closest to the userDistance and which is lower
final filteredCharge = chargesJson
.cast<Map<String, dynamic>>()
.fold(<int, Map<String, dynamic>>{},
(Map<int, Map<String, dynamic>> map, element) {
final type = element['type'] as int;
// If the type of charge is not entered,I enter it
// If the type exists then I replace it by the highest distance but less than userDistance
if ((element['distance'] as int) <= userDistance) {
if (!map.containsKey(type) || (map[type]['distance'] as int) < (element['distance'] as int)) {
map[type] = element;
}
}
return map;
})
.values
.toList();
for(int i = 0; i < filteredCharge.length; i++){
int initialBond = filteredCharge[i]['bond'];
int initialDistance = filteredCharge[i]['distance'];
int initialHausse = filteredCharge[i]['hausse'];
int differenceDistance = userDistance - initialDistance;
double updateHausse = initialHausse - ((initialBond / 100) * differenceDistance);
// I update my object with distance and hausse
filteredCharge[i]['hausse'] = updateHausse.round();
filteredCharge[i]['distance'] = userDistance;
}
// Keep the object that has the closest rise to 1100
switch (filteredCharge.length) {
case 0:
// no result
break;
case 1:
// one result
result = filteredCharge;
break;
default:
// Several results I have to sort
// I have to look who is closest to the 1100 rise
// For this I compare the value in absolute and I enter it in value
for(int i = 0; i < filteredCharge.length; i++){
int updatedHausse = filteredCharge[i]['hausse'];
int differenceHausseAbsolute = (1100 - updatedHausse).abs();
filteredCharge[i]['absHausse'] = differenceHausseAbsolute;
}
// I rearrange the order to have the smallest upside difference first
filteredCharge.sort((a, b) => (a['absHausse']).compareTo(b['absHausse']));
result = filteredCharge;
}
return result;
}
// List which keeps the charges which correspond to my need
// I use it if I ever have to switch
List selectedAllCharge = searchCharges(userDistance);
// My result is the first
Map selectedCharge = selectedAllCharge.first;
// function that gives me the values ​​around
List searchEncadrementDistanceForCharge(Map selectedCharge) {
int selectedChargeNumber = selectedCharge['type'];
var result = <Map<String, dynamic>>[];
//I keep object who have the same type of my selectedCharge
List altitudesJsonForCharge = altitudesJson.where((c) => c['type'] == selectedChargeNumber ).toList();
// If I have results
if(altitudesJsonForCharge.length != 0) {
// I look if I have a distance values = userDistance
List distanceEgale = altitudesJsonForCharge.where((a) => a['distance'] == userDistance).toList();
// If I have I enter this
if(distanceEgale.length > 0){
result.add(distanceEgale.first);
}else{
// I have no equality
// I sort the list to have all the objects that have a lower distance
List allDistancesInferior = altitudesJsonForCharge.where((a) => a['distance'] < userDistance).toList();
// I sort the list to have all the objects that have a greater distance
List allDistancesSuperior = altitudesJsonForCharge.where((a) => a['distance'] > userDistance).toList();
// I enter the result in my list
if (allDistancesInferior.isNotEmpty) {
// I enter the lower value
result.add(allDistancesInferior.last);
}
if (allDistancesSuperior.isNotEmpty) {
// I enter the higher value
result.add(allDistancesSuperior.first);
}
}
}
return result;
}
List encadrementDistance = searchEncadrementDistanceForCharge(selectedCharge);
print(encadrementDistance.length);
},
),
],
when I print all my values, in the middle of the print of "allDistanceInferior", I have the final print of "encadrementDistance.length" which appears with the print of "allDistancesSuperior"
I'm new in Dart and Flutter, how to fix that ?

Dart is an asynchronous language.
It means it will not wait for the end of a function/method.
All you have to do is have functions return a Future and call the function with await.
You can use a Future builder or make use of setState and StatefulWidget to update gui when you know all your calculations are finished.

Related

Render lit / lit-html TemplateResult as string

In lit/lit-html/lit-element, a standard component is the TemplateResult (usually HTMLTemplateResult), created like:
function renderMe(msg) {
return html`<div>Hello ${msg}!</div>`;
}
and of course the power and efficiency of the library is that subsequent calls will reuse the same <div> Element and only replace the changed fragments.
For testing the renderMe() function above, however, it would be helpful to be able to see the return value as a standard string, like:
assert.equal(RENDER_AS_STRING(renderMe('kimiko')), '<div>Hello kimiko!</div>');
and fix any bugs in the function before testing how it renders into the browser itself.
Is there a function like RENDER_AS_STRING either in lit itself or in a testing library? I have searched and not found one.
The result of execution contains html strings and values that alternate:
We can combine them in the same order:
function renderMe(msg) {
return html`<div>Hello ${msg}!</div>`;
}
const getRenderString = (data) => {
const {strings, values} = data;
const v = [...values, ''] // + last emtpty part
return strings.reduce((acc,s, i) => acc + s + v[i], '')
}
console.log(getRenderString(renderMe('SO')))
You can test it in the playground
And the recursive version
import {html, css, LitElement} from 'lit';
function renderMe(msg) {
return html`<p>Hello ${msg}!</p>`;
}
function renderBlock(msg) {
return html`<div>${renderMe(msg)}</div>`;
}
const getRenderString = (data) => {
const {strings, values} = data;
const v = [...values, ''].map(e => typeof e === 'object' ? getRenderString(e) : e )
return strings.reduce((acc,s, i) => acc + s + v[i], '')
}
document.getElementById('output').textContent = getRenderString(renderBlock('SO'))
#Daniil Loban's answer works great if the arguments are strings, but if they might themselves be TemplateResults or arrays of TemplateResults (which are all allowed by spec), it needs a more complex answer:
export function template_as_string(data) {
const {strings, values} = data;
const value_list = [...values, '']; // + last empty part
let output = '';
for (let i = 0; i < strings.length; i++) {
let v = value_list[i];
if (v._$litType$ !== undefined) {
v = template_as_string(v); // embedded Template
} else if (v instanceof Array) {
// array of strings or templates.
let new_v = '';
for (const inner_v of [...v]) {
new_v += template_as_string(inner_v);
}
v = new_v;
}
output += strings[i] + v;
}
return output;
}

Expected a value of type 'string' but got one of type 'int' - Flutter

I have a function that returns a String, but when I call this function, the app screen goes red and I get this error: Expected a value of type 'string' but got one of type 'int'.
Here is my function that returns a String:
checkProportion(String predominantGamete, String resultado) {
var countBrown = 0;
var countBlack = 0;
var countWhite = 0;
var proportionCamundongo =
'Proporção: ${countBrown}:${countBlack}:${countWhite}';
if (predominantGamete == 'recessiva_aa' &&
resultado.contains('A') &&
resultado.contains('P')) {
return countBrown += 1;
} else if (predominantGamete == 'recessiva_aa' &&
resultado.contains('A') &&
resultado.contains('pp')) {
return countBlack += 1;
} else if (predominantGamete == 'recessiva_aa' &&
resultado.contains('aa')) {
return countWhite += 1;
}
return proportionCamundongo;
}
Here is how I call the function:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
title: Text(
checkProportion(widget.predominant, widget.result),
),
),
How to solve this error?
Here is an image that shows the colors of each result:
The issue here is that you are returning early, not breaking the if statement, when you do something like return countBrown += 1;;
Try incrementing the counters, then using string interpolation to display the value:
String checkProportion(String predominantGamete, String resultado) {
int countBrown = 0;
int countBlack = 0;
int countWhite = 0;
if (predominantGamete == 'recessiva_aa' &&
resultado.contains('A') &&
resultado.contains('P')) {
countBrown += 1;
} else if (predominantGamete == 'recessiva_aa' &&
resultado.contains('A') &&
resultado.contains('pp')) {
countBlack += 1;
} else if (predominantGamete == 'recessiva_aa' &&
resultado.contains('aa')) {
countWhite += 1;
}
return 'Proporção: ${countBrown}:${countBlack}:${countWhite}';
}
I'd also recommend specifing the return type of the function (String), using the correct types for counters (int). That will help your compiler catch the issues as well.
It isn't my best work, and there is probably a better way to check for if a string contains all occurrence of multiple substrings, but here you go:
bool isColorContained(String resultado, Set<String> requirements) {
for(String requirement in requirements) {
if (!resultado.contains(requirement)) {
return false;
}
}
return true;
}
 
String checkProportion(String predominantGamete, String resultado) {
Map<ColorType, Set<String>> colorType = {
ColorType.brown: {'A', 'P'},
ColorType.black: {'A', 'pp'},
ColorType.white: {'aa'},
};
Map<ColorType, int> colorTypeCount = {
ColorType.brown: 0,
ColorType.black: 0,
ColorType.white: 0,
};
for(MapEntry<ColorType, Set<String>> entry in colorType.entries ) {
if(predominantGamete != 'recessiva_aa') continue;
bool contained = isColorContained(resultado, entry.value);
if(contained) {
int count = colorTypeCount[entry.key] ?? 0;
colorTypeCount[entry.key] = count + 1;
}
}
return 'Proporção: ${colorTypeCount[ColorType.brown]}:${colorTypeCount[ColorType.black]}:${colorTypeCount[ColorType.white]}';
}
 
Also, declare the ColorType enum:
enum ColorType {
brown, black, white
}
This will scale with as many colors and requirements you have, by adding to the ColorType enum, the colorType map, and the colorTypeCount map.

How do I sort a list of element according to Delivery time of the orders in dart, Flutter?

I am fetching a list of orders and storing the objects in a List. The object has a property called String deliveryTime and the times are in 'hh:mm a' format. I want to sort the list by the deliveryTime of the objects in Ascending order. I created a list of String that has the deliveryTime only and used bubble sort to sort them in ASCENDING order. But I am having trouble sorting the entire list of objects in that order.
NOTE: The list of object has some null & "ASAP" as their deliveryTime value.
Here's the incomplete code:
List<OnlineDeliveryOrder> getSortedOrdersList(
List<OnlineDeliveryOrder> orderList,
) {
List<OnlineDeliveryOrder> tempOrderList = [];
List<DateTime> sortedTimeList = [];
print("List Length before Sort: " + orderList.length.toString());
orderList.forEach((OnlineDeliveryOrder order) {
if (order.deliveryTime != null && order.deliveryTime != "ASAP")
sortedTimeList.add(DateFormat('hh:mm a').parse(order.deliveryTime));
});
sortedTimeList =
sortedTimeList.toSet().toList(); //Taking the unique times only
//Sorting times in asc order using bubble sort algorithm
bool sorted = false;
while (!sorted) {
sorted = true;
for (int i = 0; i < sortedTimeList.length - 1; i++) {
DateTime tempTime;
if (sortedTimeList[i].compareTo(sortedTimeList[i + 1]) == 1) {
// dt1.compareTo(dt2) == 1 if dt1 is a later date than dt2
tempTime = sortedTimeList[i];
sortedTimeList[i] = sortedTimeList[i + 1];
sortedTimeList[i + 1] = tempTime;
sorted = false;
}
}
}
// HOW DO I SORT THE ENTIRE LIST
print("List Length after Sort: " + tempOrderList.length.toString());
// String time = DateFormat('hh:mm a').format(element);
return tempOrderList;
}
Can anyone please guide me on how can I return the sorted list?
Why do you implement a sorting algorithm with O(n^2) time complexity by your own?
You can use
List<OnlineDeliveryOrder> getSortedOrdersList(List<OnlineDeliveryOrder> orderList){
var format = DateFormat('hh:mm a');
return List.of(orderList)..sort((a,b){
if(a.deliveryTime == null) return 1;
if(b.deliveryTime == null) return -1;
if(a.deliveryTime == 'ASAP') return 1;
if(b.deliveryTime == 'ASAP') return -1;
return format.parse(a.deliveryTime).compareTo(format.parse(b.deliveryTime));
});
}
This way, first all objects come with valid date, then with 'ASAP' and then with null as deliveryTime.
Or if you want it even more efficient without any package:
class SortObject extends Comparable<SortObject>{
static final DateFormat format = DateFormat('hh:mm a');
final OnlineDeliveryOrder order;
final DateTime? deliveryTime;
SortObject(this.order):this.deliveryTime=order.deliveryTime==null||order.deliveryTime=='ASAP'?null:format.parse(order.deliveryTime);
int compareTo(SortObject other){
if(order.deliveryTime == null) return 1;
if(other.order.deliveryTime == null) return -1;
if(order.deliveryTime == 'ASAP') return 1;
if(other.order.deliveryTime == 'ASAP') return -1;
return deliveryTime!.compareTo(other.deliveryTime!);
}
}
List<OnlineDeliveryOrder> getSortedOrdersList(List<OnlineDeliveryOrder> orderList){
return (orderList.map((a)=>SortObject(a)).toList()..sort((a,b){
return a.compareTo(b);
})).map((a)=>a.order).toList();
}
Or did I get the question wrong?
If there are errors in the code, I apologize. I just wrote it down.
I would recommend you to add in the OnlineDeliveryOrder class another attribute that stores the DateTime in addition to deliveryTime which does that as a String. Or you can store the time only as DateTime and not as String at all. If you receive the data as JSON, this is very easy to do. (This way you wouldn't need an extra class or a GroupedList).

How to fix both Found 'DD'-anomaly and only one return statement

I have some difficulties when fixing PMD warnings, this was my simplified method:
public String rank(String keyword, int pageSize, int totalPage)
{
String result = "0"; // A: DataflowAnomalyAnalysis: Found 'DD'-anomaly for variable 'result'
if (isNotBlank(keyword))
{
boolean find = false; // B: DataflowAnomalyAnalysis: Found 'DD'-anomaly for variable 'find'
for (int page = 1; page < totalPage; page++)
{
int rank = getRank(keyword, pageSize, totalPage);
if (rank != 0)
{
find = true; // B(1)
result = String.valueOf(rank); // A(1)
break;
}
}
if (!find)
{
result = format("{0}+", totalPage * pageSize - 1); // A(2)
}
}
return result;
}
I tried this and got "OnlyOneReturn" warnings:
public String rank(String keyword, int pageSize, int totalPage)
{
if (isNotBlank(keyword))
{
for (int page = 1; page < totalPage; page++)
{
int rank = getRank(keyword, pageSize, totalPage);
if (rank != 0)
{
return String.valueOf(rank); // OnlyOneReturn
}
}
return format("{0}+", totalPage * pageSize - 1); // OnlyOneReturn
}
return "0";
}
How do I have to write this code please?
A 'DD'-anomaly an a dataflow analysis tells you that you assign a variable more than once without using it between the assignments. So all but the last assignment are unnecessary. It usually indicates that you didn't separate your scenarios properly. In your case you have three scenarios:
If the keyword is blank then the return value is "0".
Otherwise loop through all pages and if getRank() returns a rank other than zero then this is the return value.
Otherwise the return value is "totalPage * pageSize - 1+"
If you implement those scenarios one by one you end up with a method that has not any dataflow or other PMD issues:
public String rank(String keyword, int pageSize, int totalPage) {
String result;
if (isNotBlank(keyword)) {
result = "0";
} else {
int rank = 0;
for (int page = 1; page < totalPage && rank == 0; page++) {
rank = getRank(keyword, pageSize, totalPage);
}
if (rank != 0) {
result = String.valueOf(rank);
} else {
result = format("{0}+", totalPage * pageSize - 1);
}
}
return result;
}
If you take a closer look at the for loop you see that page is only used for looping. It is not used inside the loop. This indicates that the for loop is probably not necessary. getRank(keyword, pageSize, totalPage) should always return the same value as its arguments never change during the loop. So it might be enough to call getRank(...) just once.

delete duplicates from a list in dart

hey there i am trying to display all of the options from my database in a dropdown,i have them displaying but i only want one of each result to appear and i cant figure out how to to get ride of the duplicates this is what it looks like when i click on the dropdown
here is the code to pull in the results
void _getFieldsData() {
getUserDetails().then((data) {
final items = jsonDecode(data).cast<Map<String, dynamic>>();
var fieldListData = items.map<User>((json) {
return User.fromJson(json);
}).toSet().toList();
///set list for class
_selectedField = fieldListData[0].series;
_selectedField = fieldListData[0].classs;
setState(() {
for (Map user in items) {
_userDetails.add(User.fromJson(user));
print(_userDetails.length);
//if (_userDetails.classs != userDetail.classs.contains(_selectedText))
}
});
// update widget
setState(() {
_fieldList = fieldListData.toSet().toList();
//print(resultseries);
// print(uniqueCount);
print(_fieldList);
});
});
here is the dropdown
new DropdownButton<String>(
hint: Text("Series"),
// value: null,
items: _fieldList.map((value){
return DropdownMenuItem<String>(
value: value.series,
child: Container(
width: 100,
child: new Text(value.series),
it's not clear exactly what your User class looks like, but im assuming you have multiple fields that do not all have same values, for example, each with a unique id, that's why the following line isn't working in your case:
setState(() {
_fieldList = fieldListData.toSet().toList();
});
i would suggest using List.fold, List.any, and change the line above to check for only .series field, as below:
List initialResultsList = [];
setState(() {
// use fold (similar to .reduce()) to iterate through fieldListData and return the updated filtered 'results'
// list with each iteration:
_fieldList = fieldListData.fold(initialResultsList, (results, currentItem) {
// check to see if currentItem.series already exists in any item of filtered results:
if (!results.any((item) => item.series == currentItem.series)) {
// if not, add it to results:
results.add(currentItem);
}
// return results for next iteration
return results;
});
}