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

Dart 如何最好地实现iterables的配分函数?,dart,Dart,我越来越喜欢dart的列表操作功能。然而,我经常发现自己需要一个“分区”函数,其中一个列表根据一个布尔标准被分成两部分。其含义与。where相同,但不会丢弃错误的 明显的执行: Iterable分区(Iterable列表、过滤器){ var匹配=[]; var非匹配=[]; 列表.forEach((e){ if(过滤器(e)){ 添加(e); }否则{ 不匹配。添加(e); } }); 返回[匹配项,非匹配项]; } 然而,我也越来越喜欢那些懒惰的iterables,它们正在那里回归 另一种实

我越来越喜欢dart的列表操作功能。然而,我经常发现自己需要一个“分区”函数,其中一个列表根据一个布尔标准被分成两部分。其含义与
。where
相同,但不会丢弃错误的

明显的执行:

Iterable分区(Iterable列表、过滤器){
var匹配=[];
var非匹配=[];
列表.forEach((e){
if(过滤器(e)){
添加(e);
}否则{
不匹配。添加(e);
}
});
返回[匹配项,非匹配项];
}
然而,我也越来越喜欢那些懒惰的iterables,它们正在那里回归

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

Iterable分区(Iterable列表、过滤器){
var matches=list.where(过滤器);
var nonMatches=list.toSet().difference(matches.toSet()).toList();
返回[匹配项,非匹配项];
}
我很高兴看到如何实现一个优雅的惰性实现(如果很容易的话)。 我相信从一个列表构造一个集合是一个
O(n)
操作,所以这两个实现在效率上不应该有太大的不同。需要对此发表评论

更新 set实现存在缺陷。我不明白为什么它不起作用,但是
非匹配项
并不包含
匹配项中未包含的所有数字

如何:

Iterable分区(Iterable列表、过滤器){
返回[list.where((e)=>filter(e)),list.where((e)=>!filter(e));
}
问候
Robert

您可以将其无缝地混合到视图中,例如
不可修改的ListView

import“包:unittest/unittest.dart”;
导入“dart:集合”;
类元组{
期末考试A;
期末考试B;
常量元组(this.a,this.b);
字符串toString(){
返回“(a:$a,b:$b)”;
}
}
抽象类partitionMixin{
Iterable,其中(布尔测试(E元素));
映射_filterCache=新映射();
元组划分(布尔过滤器(E)){
布尔缓存过滤器(E){
if(_filterCache.containsKey(e))返回_filterCache[e];
否则{
bool filterRes=过滤器(e);
_filterCache[e]=filterRes;
返回过滤器;
}
}
返回新元组(this.where(cachedFilter)),
其中((E)=>!cachedFilter(E));
}
}
类ExtULV=不可修改的ListView,带有
分裂混合素;
void main(){
测试('一分为二',(){
变量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=新元组(fooA,fooB);
测试的var=新的ExtULV([1,2,3,4,5,6,7,8,9,10,11,12,13,14]);
var testRes=tested.partition(foo);
打印(“fooRes:$fooRes\ntestRes:$testRes”);
expect(testRes.a.toList().toString()==fooRes.a.toString(),true);
expect(testRes.b.toList().toString()==fooRes.b.toString(),true);
});
}

如果你对它进行概括,它会变得更简单

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

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

我做了一些基准测试。集合的构造比我预期的慢得多,
forEach
实现似乎比拆分随机生成的100000个int数据集快了大约90%。我认为第一个实现非常好。如果你真的想懒惰的话,这将复杂得多。您将返回两个自定义iterable,它们在原始iterable上共享一个迭代器,并且当您将其中一个返回的iterable的迭代推进到目前为止构建的列表之前时,会以增量方式构建基础列表。这是可行的,但肯定不值得付出努力。@lrn我们需要更深入“重载所有访问方法并在直接访问时生成集合元素。进行虚拟收藏:p感谢您的建议,但是有两次迭代,对于过滤器计算成本很高的情况,您不想重复两次。缓存的有趣解决方案。我得到一个错误,ExtULV抱怨它不能接受对自身的引用。只需删除partitionMixin的类型规范,就可以很好地工作,比如带有partitionMixin的
class ExtULV=UnmodifiableListView@tusj感谢您的反馈!类型注释是可选的,因此可以删除它。我使用的是1.5.0.devSDK,可能这就是我没有这个问题的原因。我做了更多的基准测试。缓存比forEach更适合进行足够严格的比较。(以递归斐波那契为例)。