I'm trying to add all elements in a list of lists by index and average them:
List<List<double>> data = [[1.0, 2.0, 3.0], [2.0, 3.0, 5.0], [8.0, 7.0, 2.0]]
The result should be a list of doubles each summed up and then divided by the total lengths of above data:
[11.0, 12.0, 10.0] // divide these by 3
[3.67, 4.0, 3.33] // should be the result
What is the best way to do this? This is taking too long in my flutter app (actual data list contains 60 lists of 2000 doubles each) and yes, I am also asserting the length of each list is equal. and is not empty or having unexpected data types.
Well I really don't know about the speed you need.
Try this method to see if it works for your dataset. Maybe your method is faster!
void main() {
List<List<double>> data = [[1.0, 2.0, 3.0], [2.0, 3.0, 5.0], [8.0, 7.0, 2.0]];
List<double> dataSum = List<double>();
// original data
print(data);
for (var item in data){
dataSum.add(item.fold(0, (p, c) => p + c) / item.length);
}
// output
print(dataSum);
}
Important:
Anyways, if you do a large task in time, you can use a async function with a Future to prevent the application to hang and not suffer because of the long wait.
UPDATE: After OP's comment
This code should give you the result you are expecting.
void main() {
List<List<double>> data = [[1.0, 2.0, 3.0], [2.0, 3.0, 5.0], [8.0, 7.0, 2.0]];
int numLists = data.length;
int numElements = data[0].length;
double sum;
List<double> dataSum = List<double>();
for(var i = 0; i < numElements; i++ ) {
sum = 0.0;
for(var j = 0; j < numLists; j++ ) {
sum += data[j][i]; //inverted indexes
}
dataSum.add(sum/numLists);
}
// output
print(dataSum);
}
My contribution for a Matrix NxM, I've modified your data for a more generic solution:
extension chesu<T> on List<List<T>> {
List<List<T>> transpose() {
final rowNum = this.length;
final colNum = this[0].length;
var list = List<List<T>>.generate(colNum, (i) => List<T>());
if (rowNum == 0 || colNum == 0) return null;
for (var r = 0; r < rowNum; r++)
for (var c = 0; c < colNum; c++) list[c].add(this[r][c]);
return list;
}
}
main(List<String> args) {
final data = [[1.0, 2.0, 3.0, 4.0], [2.0, 3.0, 5.0, 8.0], [6.0, 7.0, 7.0, 9.0]];
print(data.transpose().map((e) => e.reduce((v, e) => v+e)).map((e) => e/3));
}
Result:
(3.0, 4.0, 5.0, 7.0)
There is a new package named scidart that contains interesting functions like transpose, it tries to emulate numpy from Python.
UPDATE 1: Working with Big Data
UPDATE 2: I made a fool mistake with sum(), extension is fixed now, sorry.
import 'dart:math';
extension on List<List<double>> {
List<List<double>> transpose() {
final rowNum = this.length;
final colNum = this[0].length;
var list = List<List<double>>.generate(colNum, (i) => List<double>());
if (rowNum == 0 || colNum == 0) return null;
for (var r = 0; r < rowNum; r++)
for (var c = 0; c < colNum; c++) list[c].add(this[r][c]);
return list;
}
List<double> sum() => this.map((l) => l.reduce((v, e) => v+e)).toList();
}
class Stats {
List<List<double>> _data;
int _rows, _cols;
List<double> _sum, _avg;
Stats(List<List<double>> data) {
_data = data.transpose();
_rows = _data.length;
_cols = _data[0].length;
}
int get rows => _rows;
int get cols => _cols;
List<double> get sum {
if ([0, null].contains(_sum)) _sum = _data.sum();
return _sum;
}
List<double> get avg {
if ([0, null].contains(_avg)) _avg = sum.map((e) => e / _cols).toList();
return _avg;
}
}
main(List<String> args) {
// final data = [[1.0, 2.0, 3.0, 4.0], [2.0, 3.0, 5.0, 8.0], [6.0, 7.0, 7.0, 9.0]];
// final data = [[1.0, 2.0, 3.0], [2.0, 3.0, 5.0], [8.0, 7.0, 2.0]];
final data = List<List<double>>.generate(60, (i) => List<double>.generate(2000, (j) => Random().nextDouble()*30));
print('Creating big data...');
final stats = Stats(data);
final stopwatch = Stopwatch()..start();
print('Calculating statistics...');
print('Sum: ${stats.sum.take(5)}');
print('Average: ${stats.avg.take(5)}');
stopwatch.stop();
print('\nJob finished at ${stopwatch.elapsedMilliseconds/1000} seconds.');
}
Result:
Creating big data...
Calculating statistics...
Sum: (928.8075263386316, 934.3418807027017, 815.2172548417801, 833.6855783984151, 828.1013228547513)
Average: (15.480125438977193, 15.572364678378362, 13.586954247363002, 13.894759639973586, 13.801688714245854)
Job finished at 0.024 seconds.
For operations on list you have to iterate over it's items (for, map, forEach ...etc) which would take time (depending on the list length) so I guess you have to do some benchmarking.
Try this
List<double> sum = [];
List<double> average = [];
sum = data.reduce((a, b) {
List<double> list = [];
for (int i = 0; i < b.length; i++) {
list.add(a[i] + b[i]);
}
return list;
});
average = sum.map((e) => e / 3).toList();
print(sum);
print(average);
Let me suggest more compact solution:
List<List<double>> data = [[1.0, 2.0, 3.0], [2.0, 3.0, 5.0], [8.0, 7.0, 2.0]]
var result = <double>[];
final innerListSize = data[0].length;
for (int i = 0; i < innerListSize; i++) {
result.add(data.map((e) => e[i]).average);
}
Related
I'm trying to sum Map values. but i am getting error. I think it's because Map returns null. I will be glad if you help.
I try that code;
void main() {
List t = ['tag1', 'tag2'];
List f = ['1', '2', '3'];
List data = [
['1', 0.5, 0.6],
['2', 0.7, 0.8],
['3', 0.9, 1]
];
Map answers = {};
for (final i in data) {
answers[i[0]] = i.skip(1);
}
var qSum = 0.0;
for (int tg = 0; tg < t.length; tg++) {
for (final i in f) {
var val = answers[i][tg];
qSum = qSum + (val);
}
}
}
It's because skip returns an Iterable and not a List. Change
answers[i[0]] = i.skip(1);
to
answers[i[0]] = i.skip(1).toList();
I have 2 list
List a = [0,2,0];
List b = [0,3,0];
Now I want to create a function to calculate this list and return a list of percentages.
Return [0,67,0]
void main() {
getPercentage();
}
int? getPercentage(){
List<int> a = [0,2,0];
List<int> b = [0,3,0];
for (int i = 0; i < a.length; i++) {
int percentage = ((a[i]/b[i]*100).toInt());
return percentage;
}
}
I tried this.
The issue occurs when the number is divided by 0
You can replace 0 with 1.
List<int>? getPercentage() {
List<int> a = [0, 2, 0];
List<int> b = [0, 3, 0];
List<int> percentage = [];
for (int i = 0; i < a.length; i++) {
int x = a[i] <= 0 ? 1 : a[i];
int y = b[i] <= 0 ? 1 : b[i];
final p = (x / y * 100).toInt();
percentage.add(p);
}
return percentage;
}
void main() {
print(getPercentage()); //[100, 66, 100]
}
The following should work:
void main() {
getPercentage();
}
List<int> getPercentage(){
List<int> a = [0,2,0];
List<int> b = [0,3,0];
List<int> result = [];
for (int i = 0; i < a.length; i++) {
int percentage = b == 0 ? 0 : (a[i] / b[i] * 100).toInt();
result.add(percentage);
}
return result;
}
Alternatively use this function for any A/B int list with nan check:
List<int> getPercentage(List<int> ListA, List<int> ListB) {
int maxLength = min(ListA.length, ListB.length); // check if has same # items
List<int> result = [];
for (int i = 0; i < maxLength; i++) {
var calc = (ListA[i] / ListB[i]) * 100; // calc % A/B of item i
calc = (calc).isNaN ? 0 : calc; //check if is nan (divided by zero) return 0
result.add((calc).toInt()); //add to result list
}
return result;
}
There is a string with random numbers and letters. I need to divide this string into 5 parts. And get List. How to do it? Thanks.
String str = '05b37ffe4973959c4d4f2d5ca0c1435749f8cc66';
Should work:
List<String> list = [
'05b37ffe',
'4973959c',
'4d4f2d5c',
'a0c14357',
'49f8cc66',
];
I know there'a already a working answer but I had already started this so here's a different solution.
String str = '05b37ffe4973959c4d4f2d5ca0c1435749f8cc66';
List<String> list = [];
final divisionIndex = str.length ~/ 5;
for (int i = 0; i < str.length; i++) {
if (i % divisionIndex == 0) {
final tempString = str.substring(i, i + divisionIndex);
list.add(tempString);
}
}
log(list.toString()); // [05b37ffe, 4973959c, 4d4f2d5c, a0c14357, 49f8cc66]
String str = '05b37ffe4973959c4d4f2d5ca0c1435749f8cc66';
int d=1
; try{
d = (str.length/5).toInt();
print(d);
}catch(e){
d=1;
}
List datas=[];
for(int i=0;i<d;i++){
var c=i+1;
try {
datas.add(str.substring(i * d, d*c));
} catch (e) {
print(e);
}
}
print(datas);
}
OR
String str = '05b37ffe4973959c4d4f2d5ca0c1435749f8cc66';
int d = (str.length / 5).toInt();
var data = List.generate(d - 3, (i) => (d * (i + 1)) <= str.length ? str.substring(i * d, d * (i + 1)) : "");
print(data);//[05b37ffe, 4973959c, 4d4f2d5c, a0c14357, 49f8cc66]
If you're into one liners, with dynamic parts.
Make sure to import dart:math for min function.
This is modular, i.e. you can pass whichever number of parts you want (default 5). If you string is 3 char long, and you want 5 parts, then it'll return 3 parts with 1 char in each.
List<String> splitIntoEqualParts(String str, [int parts = 5]) {
int _parts = min(str.length, parts);
int _sublength = (str.length / _parts).ceil();
return Iterable<int>
//Initialize empty list
.generate(_parts)
.toList()
// Apply the access logic
.map((index) => str.substring(_sublength * index, min(_sublength * index + _sublength, str.length)))
.toList();
}
You can then use it such as print(splitIntoEqualParts('05b37ffe4973959c4d4f2d5ca0c1435749f8cc66', 5));
splitWithCount(String string,int splitCount)
{
var array = [];
for(var i =0 ;i<=(string.length-splitCount);i+=splitCount)
{
var start = i;
var temp = string.substring(start,start+splitCount);
array.add(temp);
}
print(array);
}
I implemented select sort in Flutter and in SwiftUI. I made the implementations as similar as possible.
Swift:
func selectSort(list: inout [Double]) -> [Double] {
for i in 0..<list.count {
var minElPos = i;
for j in (minElPos + 1)..<list.count {
if list[j] < list[minElPos] {
minElPos = j;
}
}
// swap
let temp = list[i];
list[i] = list[minElPos];
list[minElPos] = temp;
}
return list;
}
// Measuring time
func generateRandomList(size: Int) -> [Double] {
var res = Array<Double>(repeating: 0.0, count: size)
for i in 0..<size {
res[i] = Double.random(in: 0...1)
}
return res;
}
var arrayToTest: [Double] = generateRandomList(size: 8000);
let startingPoint = Date()
selectSort(list: &arrayToTest);
let time = startingPoint.timeIntervalSinceNow * -1;
Flutter:
class SelectSort {
static List<double> call(List<double> list) {
for(int i = 0; i < list.length - 1; i++) {
int minElPos = i;
for(int j = minElPos + 1; j < list.length; j++) {
if(list[j] < list[minElPos]) {
minElPos = j;
}
}
// swap
double temp = list[i];
list[i] = list[minElPos];
list[minElPos] = temp;
}
return list;
}
}
// Measuring time
class Utils {
static List<double> generateRandomList(int nbOfElements) {
var random = new Random();
List<double> res = List(nbOfElements);
for (var i = 0; i < nbOfElements; i++) {
res[i] = random.nextDouble();
}
return res;
}
}
List<double> arrayToTest = Utils.generateRandomList(8000);
final stopwatch = Stopwatch()..start();
SelectSort.call(arrayToTest);
stopwatch.stop();
int time = stopwatch.elapsedMilliseconds;
I measured the execution time for an array of random numbers. The array size is 8000. Flutter needs 0.053s and SwiftUI needs 0.141s. Does anyone have a clue why flutter as a hybrid framework has better performance than a native solution?
Both apps were run in release mode on a physical device.
I have been looking at Dart and I was wondering if it has a range operator like the one Kotlin has
https://kotlinlang.org/docs/reference/ranges.html
or anything similar to that.
You could use List.generate, like this:
var list = List.generate(4, (i) => i);
print(list); // prints [0, 1, 2, 3]
Or
List _range(int from, int to) => List.generate(to - from + 1, (i) => i + from);
print(_range(3, 6)); // prints [3, 4, 5, 6]
There is no such operator in Dart at the current time.
For quite some time (since September 2014), Iterable.generate(n) has been available which iterate integers from 0 to n-1. Currently that seems to be the closed you can get to a range() like function.
See the discussion in this issue 7775
Usage example:
Iterable.generate(5).forEach((i) => print(i));
You can use range_type dart package for using ranges.
import 'package:range_type/predefined_ranges.dart';
void main() {
final july = DateTimeRange.parse('[2022-07-01, 2022-08-01)');
final scheduleDate1 = DateTime(2022, 07, 02);
final scheduleDate2 = DateTime(2022, 08, 07);
final workingDays = DateTimeRange.parse('[2022-07-20, 2022-08-15)');
print('Is scheduleDate1 in July? ${july.containsElement(scheduleDate1)}');
print('Is scheduleDate2 in July? ${july.containsElement(scheduleDate2)}');
print('Is workingDays overlaps? ${july.overlap(workingDays)}');
print('workingDays intersection: ${july.intersection(workingDays)}');
print('workingDays union: ${july.union(workingDays)}');
print('july difference workingDays: ${july.difference(workingDays)}');
}
There is no such operator in Dart at the current time.
but try these codes
1.
List<int> range(int from, int from)=>List.generate(10,(i)=>i);
Iterable<int> range(int from,int to,[int stepSize=1]) sync*{
for(int i = from;i<to;i+=stepSize){
yield i;
}
}
Iterable<int> to(int end, [int stepSize = 1]) sync* {
if (this <= end) {
for (var i = this; i < end; i += stepSize) yield i;
} else {
for (var i = this; i > end; i -= stepSize) yield i;
}
}
}