在飞镖中访问 fold/reduce 中的上一个元素

accessing previous element in fold/reduce in dart

不知能否重写这段dart代码:

 double length = 0;
 Point current = points.first;
 for (var next in points.skip(1)){
   length += current.distanceTo(next);
   current = next;
 }
 return length;

更简洁优雅的东西。我正在考虑使用 reduce / fold,但是有没有办法在组合函数中访问可迭代的先例元素?

总有一种方法可以替代带有可迭代的 for 循环。
在这里实现了斐波那契逻辑并检查了性能。

import 'dart:math';

double fibSum = 0;
double quesSum = 0;
List<Point> listOfPoints = [Point(0, 0), Point(1, 1), Point(1, 4)];

void main() {
  print("before fibonacciLogic: ${DateTime.now()}");
  fibonacciLogic(listOfPoints.length);
  print("after fibonacciLogic: ${DateTime.now()}");

  print("before logicFromQuestion(): ${DateTime.now()}");
  logicFromQuestion();
  print("after logicFromQuestion(): ${DateTime.now()}");

  print("output fibonacciLogic: $fibSum");
  print("output logicFromQuestion: $quesSum");
}

fibonacciLogic(int length) {
  if (length < 2) {
    return length;
  }
  fibSum += listOfPoints
      .elementAt(length - 2)
      .distanceTo(listOfPoints.elementAt(length - 1));
  return fibonacciLogic(length - 2) + fibonacciLogic(length - 1);
}

logicFromQuestion() {
  Point current = listOfPoints.first;
  for (var next in listOfPoints.skip(1)) {
    quesSum += current.distanceTo(next);
    current = next;
  }
  return quesSum;
}

输出:

before fibonacciLogic: 2020-04-22 14:39:37.170
after fibonacciLogic: 2020-04-22 14:39:37.172
before logicFromQuestion(): 2020-04-22 14:39:37.172
after logicFromQuestion(): 2020-04-22 14:39:37.173
output fibonacciLogic: 4.414213562373095
output logicFromQuestion: 4.414213562373095

结果: 这里有问题的 for 循环逻辑需要 2 微秒,而斐波那契逻辑只需要 1.

好吧,这是我找到的答案——使用额外的对象(它似乎也稍微快一点):

class Point {
  int x;
  Point(this.x);
  int distanceTo(Point p) {
    return p == null ? 0 : (x - p.x).abs();
  }
}
class PointAccumulator {
  Point current;
  int length = 0;
  PointAccumulator(this.current);
}
void main() {
  List<Point> points = [Point(1), Point(10), Point(20)];
  int loops = 1000000;
  int length = 0;
  Stopwatch s = Stopwatch();
  s.start();
  for (var i = 0; i < loops; i++) {

    // Standard method
    length = 0;
    Point current = points.first;
    for (var next in points.skip(1)) {
      length += current.distanceTo(next);
      current = next;
    }


  }
  s.stop();
  print(s.elapsed);
  print(length);
  PointAccumulator pa;
  s = Stopwatch();
  s.start();
  for (var i = 0; i < loops; i++) {

    // with extra object
    pa = points.fold(PointAccumulator(points.first),
        (PointAccumulator pa, Point next) {
      pa.length += next.distanceTo(pa.current);
      pa.current = next;
      return pa;
    });



  }
  s.stop();
  print(s.elapsed);
  print(pa.length);
}

具有函数式编程风格和 dart 扩展方法:

extension MyExtensions<T> on Iterable<T> {
  T foldByPairs(T initialValue, T combine(T value, T previous, T current)) {
    Iterator<T> iterator = this.iterator;
    iterator.moveNext(); // error handling omitted for brevity
    T value = initialValue;
    T previous = iterator.current;
    while (iterator.moveNext()) {
      T current = iterator.current;
      value = combine(value, previous, current);
      previous = current;
    }
    return value;
  }
}