如何最好地实现iterables的分区函数?

时间:2014-06-01 22:00:45

标签: dart

我非常喜欢飞镖的列表操作功能。但是,我经常发现自己处于需要分区的状态。 function,其中列表根据布尔条件分为两部分。含义与.where相同,但不会丢弃虚假的内容。

明显的实施:

Iterable partition(Iterable list, filter) {
  var matches    = [];
  var nonMatches = [];
  list.forEach((e) {
    if (filter(e)) {
      matches.add(e);
    } else {
      nonMatches.add(e);
    }
  });
  return [matches, nonMatches];
}

但是,我也喜欢where正在返回的懒惰迭代。

另一种实现方式是使用集合:

Iterable partition(Iterable list, filter) {
  var matches    = list.where(filter);
  var nonMatches = list.toSet().difference(matches.toSet()).toList();
  return [matches, nonMatches];
}

我很高兴看到如何做一个优雅的懒惰实现(如果它很容易)。 我相信从列表构建一个集合是一个O(n)操作,所以这两个实现的效率不应该太大。评论就是这样。

更新 设定的实施是有缺陷的。我不确切地知道它为什么不起作用,但nonMatches不包含matches中未包含的所有数字。

3 个答案:

答案 0 :(得分:3)

怎么样:

Iterable partition(Iterable list, filter) {
  return [list.where((e) => filter(e)), list.where((e) => !filter(e))];
}

此致 罗伯特

答案 1 :(得分:2)

您可以将其无缝混合到视图中,例如UnmodifiableListView

import "package:unittest/unittest.dart";
import "dart:collection";

class Tuple<A,B> {
  final A a;
  final B b;
  const Tuple(this.a, this.b);
  String toString() {
    return "(a: $a, b : $b)";
  }
}

abstract class  partitionMixin<RES, E>{
  Iterable<E> where(bool test(E element));
  Map<E, bool> _filterCache = new Map();
  Tuple<RES,RES> partition(bool filter(E e)) {
    bool cachedFilter(E e) {
      if (_filterCache.containsKey(e)) return _filterCache[e];
      else {
        bool filterRes = filter(e);
        _filterCache[e] = filterRes;
        return filterRes;
      }
    }
    return new Tuple(this.where(cachedFilter),
        this.where((E e) => !cachedFilter(e)));
  }
}


 class  ExtULV<E> = UnmodifiableListView<E> with
                              partitionMixin<ExtULV<E>,E>;

void main() {

  test('Split one iterable in two"', () {

    var foo = (e) => (e % 2) == 0;
    var fooA =  [2,4,6,8, 10, 12, 14];
    var fooB =  [1,3,5,7,9,11,13];
    var fooRes = new Tuple(fooA, fooB);

    var tested = new ExtULV([1,2,3,4,5,6,7,8,9,10,11,12,13,14]);
    var testRes = tested.partition(foo);
    print("fooRes : $fooRes\ntestRes: $testRes");
    expect(testRes.a.toList().toString() == fooRes.a.toString(), true);
    expect(testRes.b.toList().toString() == fooRes.b.toString(), true);

  });
}

答案 2 :(得分:1)

如果你概括它就会变得更简单

  Map groupedBy(f, list) {
    var grouped = {};
    for (var thing in list) {
      grouped.putIfAbsent(f(thing), () => []).add(thing);  
    }
   return grouped;
  }

虽然让它变得懒惰并不容易。