【问题标题】:Dart sum list of lists by element按元素列出的 Dart 总和列表
【发布时间】:2021-02-12 20:59:25
【问题描述】:

我正在尝试按索引添加列表列表中的所有元素并将它们平均:

List<List<double>> data = [[1.0, 2.0, 3.0], [2.0, 3.0, 5.0], [8.0, 7.0, 2.0]]

结果应该是一个双精度列表,每个加起来然后除以上述数据的总长度:

[11.0, 12.0, 10.0] // divide these by 3
[3.67, 4.0, 3.33] // should be the result

最好的方法是什么?这在我的颤振应用程序中花费了太长时间(实际数据列表包含 60 个列表,每个列表包含 2000 个双精度数),是的,我还断言每个列表的长度是相等的。并且不为空或具有意外的数据类型。

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    我对 Matrix NxM 的贡献,我已修改您的数据以获得更通用的解决方案:

    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));
    }
    

    结果:

    (3.0, 4.0, 5.0, 7.0)
    

    有一个名为 scidart 的新包包含有趣的函数,例如 transpose,它试图从 Python 中模拟 numpy

    更新 1:使用大数据

    更新 2:我在 sum() 上犯了一个愚蠢的错误,extension 现在已修复,抱歉。

    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.');
    }
    

    结果:

    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.
    

    【讨论】:

    • 嘿伙计,你的数据有问题。在我的手机和 dartpad 上只花了大约 2-3 秒。这是最好的,最全面的答案。非常感谢您也提供了计算这些统计数据的示例。
    • 我用 sum() 犯了一个愚蠢的错误,扩展现已修复,抱歉。
    • 这在 Dart 上的表现令人惊叹。 Python 需要相当长的时间,即使它是最优化的版本。准确地说,大约是 4 秒。无论如何,再次感谢
    【解决方案2】:

    对于列表上的操作,您必须迭代它的项目(for、map、forEach ...等),这需要时间(取决于列表长度)所以我想您必须做一些基准测试。

    试试这个

      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);
    

    【讨论】:

    • 非常快的结果,大约需要 2 秒,谢谢!
    【解决方案3】:

    嗯,我真的不知道你需要的速度。

    试试这个方法,看看它是否适用于您的数据集。也许你的方法更快!

    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);
    }
    

    重要: 无论如何,如果您及时完成一项大型任务,您可以使用async 函数和Future 来防止应用程序挂起并且不会因为长时间等待而受到影响。


    更新:在 OP 发表评论后

    这段代码应该会给你你期望的结果。

    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);
    }
    

    【讨论】:

    • 代码看起来不错,谢谢。但是它给出的结果是错误的:[2, 3.3333333333333335, 5.666666666666667],什么时候应该是[3.67, 4.0, 3.33]
    • (1+2+8)/3 = 3.67 应该是第一个元素
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-01-12
    • 2020-01-21
    • 1970-01-01
    • 2019-09-24
    • 2022-07-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多