接上篇 dart collection 库,下面是 dart collection 库对一些已有类型的扩展。
ComparatorExtension
extension ComparatorExtension<T> on Comparator<T>
- inverse:倒过来的排序器
then(Comparator<T> tieBreaker) → Comparator<T>
:连接多个排序器,当前面的排序器认为相等时,再用后一个排序器compareBy<R>(T keyOf(R)) → Comparator<R>
:就是先将集合中的元素用参数的这个转换函数转换了,然后再用原来的比较器去比较转换后的值
var list = ['ab', 'cd', 'def'];
comparator(String a, String b){ // 按长度排序
return b.length-a.length;
}
print([...list]..sort(comparator)); // [def, ab, cd] 正常排序
print([...list]..sort(comparator.inverse)); // [ab, cd, def],逆序
comparator2(String a, String b){ // 字符串按 ASCII 编码排序
return b.compareTo(a);
}
print([...list]..sort(comparator.then(comparator2))); // [def, cd, ab],如果第一个比较器两个相等的话,接着用后面的比较器
var list2 = ['c', 'f'];
var list3 = ['b', 'gxyz'];
var list4 = [list,list2,list3];
Comparator<List> comparator3 = comparator.compareBy((List l){ // compartor3 变量范型和参数范型对应
return l.join(); // 返回值类型是 comparator 的范型
});
// list4 的元素是 List 类型,先将它用 compareBy 那参数转换成字符串 ‘defcdab’ ‘cf', 'bgxyz'
// 然后再用 comparator 去比较三个字符串的长度
list4.sort(comparator3); // [[def, cd, ab], [b, gxyz], [c, f]]
IterableExtension
extension IterableExtension<T> on Iterable<T>
属性
- firstOrNull:第一个元素,如果集合空就返回 null
- lastOrNull:最后一个元素,如果集合空就返回 null
- singleOrNull:集合唯一的元素,如果为空或者超过一个都返回 null
过滤方法
whereNot(bool test(T element)) → Iterable<T>
:过滤出不满足参数函数判断的值whereIndexed(bool test(int index, T element)) → Iterable<T>
:过滤出符合条件的,带参数whereNotIndexed(bool test(int index, T element)) → Iterable<T>
:whereNot 和 whereIndexed 的结合firstWhereOrNull(bool test(T element)) → T?
:where 是过滤符合条件的集合,这个是过滤符合条件的第一个,如果没有返回 nullfirstWhereIndexedOrNull(bool test(int index, T element)) → T?
:就是在 firstWhereOrNull 基础上多一个 indexlastWhereOrNull(bool test(T element)) → T?
:和 firstWhereOrNull 类似,只不过它返回符合过滤条件的最后一个lastWhereIndexedOrNull(bool test(int index, T element)) → T?
:就是在 lastWhereOrNull 基础上多一个 indexsingleWhereOrNull(bool test(T element)) → T?
:寻找唯一的元素返回,如果集合空,没找到或者不止一个,就返回 nullsingleWhereIndexedOrNull(bool test(int index, T element)) → T?
:在 singleWhereOrNull 的基础上多一个 indexnone(bool test(T)) → bool
:没有满足条件的元素时返回 true
Iterable iterable = {'ab', 'def', 'Za', true, 1, 4.5, 2, false};
iterable.sample(3); // [true, false, 4.5],随机取出 3 个元素
iterable.whereNot((value)=>value is bool); // (ab, def, Za, 1, 4.5, 2),不是 bool 类型的值
iterable.whereIndexed((index, element) {
return index > 2 && element.toString().length>2;
}); // (true, 4.5, false)
iterable.whereNotIndexed((index, element) {
return index > 2 && element.toString().length>2;
}); // (ab, def, Za, 1, 2) 索引小于 2 或者长度小于等于 2
iterable.firstWhereOrNull((element)=>element.toString().length==3); // def
iterable.firstWhereIndexedOrNull((index, element)=>element.toString().length==7); // null
iterable.lastWhereOrNull((element)=>element.toString().length==3); // 4.5
iterable.singleWhereOrNull((element)=>element.toString().length==3); // false,因为有两个值长度都是 3
iterable.none((e)=>e is String); // false
排序方法
sorted([Comparator<T>? compare]) → List<T>
:进行排序,底层调用[...this]..sort(compare)
,所以它是复制一份排序后返回了新的列表,不像 sort 那样直接修改原来的列表isSorted(Comparator<T> compare) → bool
:是否使用指定排序器排过序里,更准确的说,应该是顺序是否符合这个排序器的定义sortedBy<K extends Comparable<K>>(K keyOf(T element)) → List<T>
:类似ComparatorExtension
里的compareBy
,先将集合元素用参数的转换函数转换,然后底层用默认的比较器,即a.compareTo(b)
去比较isSortedBy<K extends Comparable<K>>(K keyOf(T element)) → bool
:顺序是否符合先用转换函数转换,然后再用默认的排序器排序的结果sortedByCompare<K>(K keyOf(T element), Comparator<K> compare) → List<T>
:相比sortedBy
就是使用自定义的 Comparator 而不是用默认的isSortedByCompare<K>(K keyOf(T element), Comparator<K> compare) → bool
:顺序是否符合先用转换函数转换,再用自定义的排序器排序的结果
var sorted = iterable.sorted((v1, v2)=>v1.toString().compareTo(v2.toString()));
print(iterable); // {ab, def, Za, true, 1, 4.5, 2, false},原集合顺序不变
print(sorted); // [1, 2, 4.5, Za, ab, def, false, true]
bool isSorted = sorted.isSorted((v1, v2)=>v1.toString().compareTo(v2.toString()));
print(isSorted); // true
keyOf(t)=>t.toString().length; // 定义一个转换函数 keyOf
// 先将元素转换成字符串长度,然后底层给两个元素排序用元素的 compareTo 方法,也不修改原集合顺序
var sortedBy = iterable.sortedBy<num>(keyOf);
print(sortedBy); // [1, 2, ab, Za, def, 4.5, true, false]
print(sortedBy.isSortedBy<num>(keyOf)); // true
var myComparator = ((num a, num b)=>a.compareTo(b)).inverse; // 自定义一个比较器
var sortedByCompare = iterable.sortedByCompare<num>(keyOf, myComparator);
print(sortedByCompare); // [false, true, def, 4.5, ab, Za, 1, 2]
print(sortedByCompare.isSortedByCompare(keyOf, myComparator));
遍历方法
forEachIndexed(void action(int index, T element)) → void
:带索引遍历forEachWhile(bool action(T element)) → void
:遍历直到 action 返回 falseforEachIndexedWhile(bool action(int index, T element)) → void
:在 forEachWhile 的基础上带 indexmapIndexed<R>(R convert(int index, T element)) → Iterable<R>
:在 map() 函数的基础上带 index
iterable.forEachIndexed((index, element)=>print('$index is $element'));
iterable.forEachWhile((element) { // 遍历到 true 时结果是 false,就不遍历了,注意 true 这个不符合的也遍历到了
print(element.toString());
return element is String;
});
iterable.forEachIndexedWhile((index, element) {
print('$index is $element');
return element is String;
});
iterable.mapIndexed((index, element) {
return '$index->$element';
}); // (0->ab, 1->def, 2->Za, 3->true, 4->1, 5->4.5, 6->2, 7->false)
累积方法
reduceIndexed(T combine(int index, T previous, T element)) → T
:从前往后累计迭代,index 从 1 开始,第一个 previous 就是索引为 0 的元素foldIndexed<R>(R initialValue, R combine(int index, R previous, T element)) → R
:和 reduceIndexed 区别就是提供一个初始值,所以 index 从 0 开始
iterable.expandIndexed((index, element) {
return [element, '$element->$index'];
}); // (ab, ab->0, def, def->1, Za, Za->2, true, true->3, 1, ..., false, false->7)
// abdef[1]Za[2]true[3]1[4]4.5[5]2[6]false[7]
iterable.reduceIndexed((index, previous, element)=>'$previous$element[$index]');
// start===ab[0]def[1]Za[2]true[3]1[4]4.5[5]2[6]false[7]
iterable.foldIndexed('start===', (index, previous, element)=>'$previous$element[$index]');
分组方法
groupFoldBy<K, G>(K keyOf(T element), G combine(G? previous, T element)) → Map<K, G>
:元素用 keyOf 函数转换,作为 map 的 key,不同元素转换出来的 key 相同时,作为一组,用第二个函数将原来的值封装在一起作为值groupSetsBy<K>(K keyOf(T element)) → Map<K, Set<T>>
:groupFoldBy 是自己指定怎么组合,groupSetsBy 相当于特例,自动用 Set 组合groupListsBy<K>(K keyOf(T element)) → Map<K, List<T>>
:也是 groupFoldBy 的特例,用 List 组合
var map = iterable.lastBy((t)=>t.toString().length);
print(map); // {2: Za, 3: 4.5, 4: true, 1: 2, 5: false},2 一开始的值是 ab,然后被后面的 za 覆盖
// 先用 keyOf 将所有的值转成函数第一个范型 int 的值,如果不同的值转换后结果一样的话,这些值要组合在一起
// 用第二个函数 combine 组合,combine 的第一个参数的范型是 groupFoldBy 的第二个范型,表示相同的 key 的值组合成什么结构
// 第二个参数的值是原来集合元素的类型,当前例子是 dynamic 的,函数返回类型是第一个参数的类型
combine(String? previous, element) => previous==null?element.toString():'$previous-${element.toString()}';
var map2 = iterable.groupFoldBy<int, String>(keyOf, combine);
print(map2); // {2: ab-Za, 3: def-4.5, 4: true, 1: 1-2, 5: false},组合成字符串
var map3 = iterable.groupFoldBy<int, Set<String>>(keyOf, (Set<String>? previous, element) => previous??<String>{}..add(element.toString()));
print(map3); // {2: {ab, Za}, 3: {def, 4.5}, 4: {true}, 1: {1, 2}, 5: {false}},相同的 key 组合成 set
var map4 = iterable.groupSetsBy(keyOf); // 内部指定了,就用 Set 去组合,groupFoldBy 的特例
print(map4); // {2: {ab, Za}, 3: {def, 4.5}, 4: {true}, 1: {1, 2}, 5: {false}}
var map5 = iterable.groupListsBy(keyOf); // 用 List 去组合
print(map5); // {2: [ab, Za], 3: [def, 4.5], 4: [true], 1: [1, 2], 5: [false]}
分块方法
splitBefore(bool test(T element)) → Iterable<List<T>>
:分割成块,每一块的第一个元素是用函数判断为 true 的值,然后直到再为 true,就是用返回结果判断为 true 的元素作为分界点,第一个块从第 0 个元素开始,其它块的第一个元素都是符合 test 函数判断为 true 的情况splitBeforeIndexed(bool test(int index, T element)) → Iterable<List<T>>
:就是把索引传进 test 函数,看这个函数用不用,如果不用它,和 splitBefore 没什么区别splitAfter(bool test(T element)) → Iterable<List<T>>
:和 splitBefore 倒过来,每块的最后一个元素是 test 执行为 true 的元素,最后一个块可是剩下的元素splitAfterIndexed(bool test(int index, T element)) → Iterable<List<T>>
:把索引传进 test 函数splitBetween(bool test(T first, T second)) → Iterable<List<T>>
:两个元素用 test 判断为 true 时,在这两个元素中间分隔开splitBetweenIndexed(bool test(int index, T first, T second)) → Iterable<List<T>>
:把索引传进 test 函数slices(int length) → Iterable<List<T>>
:指定长度分割切片
// 分块,参数的函数为 true 的元素作为分界点,作为块的第一个元素
iterable.splitBefore((t)=>t.toString().length==2); // ([ab, def], [Za, true, 1, 4.5, 2, false])
iterable.splitBefore((t)=>t.toString().length==3); // ([ab], [def, Za, true, 1], [4.5, 2, false])
// test 函数用到了 index,只有大于 2 才去判断长度是否等于 3,否则都是 false
// 所以 index <= 2 的情况肯定都在第一个块中
iterable.splitBeforeIndexed((index, t)=>index>2?t.toString().length==3:false); // ([ab, def, Za, true, 1], [4.5, 2, false])
// test 为 true 的作为块的最后一个元素
iterable.splitAfter((t)=>t.toString().length==2); // ([ab], [def, Za], [true, 1, 4.5, 2, false])
iterable.splitAfter((t)=>t.toString().length==3); // ([ab, def], [Za, true, 1, 4.5], [2, false])
iterable.splitAfterIndexed((index, t)=>index>2?t.toString().length==3:false); // ([ab, def, Za, true, 1, 4.5], [2, false])
// 前一个比后一个长的时候,从中间分隔开
iterable.splitBetween((first,second)=>first.toString().length>second.toString().length); // ([ab, def], [Za, true], [1, 4.5], [2, false])
// 如果在 3-4 的索引满足条件才分割
iterable.splitBetweenIndexed((index, first, second){ // ([ab, def, Za, true], [1, 4.5, 2, false])
if(index>2 && index<5) {
return first.toString().length>second.toString().length;
} else {
return false;
}
});
iterable.slices(3); // ([ab, def, Za], [true, 1, 4.5], [2, false])
其它方法
sample(int count, [Random? random]) → List<T>
:从原集合随机取出几个来组成列表elementAtOrNull(int index) → T?
:返回指定索引的元素,如果索引超出集合长度返回 null,索引必须大于等于 0,否则抛出异常expandIndexed<R>(Iterable<R> expand(int index, T element)) → Iterable<R>
:将一个元素扩展成一个集合,然后 combine 在一起返回新的集合lastBy<K>(K key(T)) → Map<K, T>
:值用转换函数转换作为 Map 的 key,原来的值作为 value,转换函数转出的 key,可能重复,前面的 value 被覆盖
IterableComparableExtension
extension IterableComparableExtension<T extends Comparable<T>> on Iterable<T>
相当于 IterableExtension
的特例,集合的元素要是可比较的。
- max/min:找出集合中最大最小值,如果集合为空,抛出异常
- maxOrNull:找出集合中最大最小值,如果集合为空,返回 null
isSorted([Comparator<T>? compare]) → bool
:是否按比较器进行排序过,和 IterableExtension 的 isSorted 区别是它的参数是可选的,因为会有一个默认的比较器
IterableNumberExtension/IterableDoubleExtension/IterableIntegerExtension
extension IterableNumberExtension on Iterable<num>
extension IterableDoubleExtension on Iterable<double>
extension IterableIntegerExtension on Iterable<int>
IterableComparableExtension
针对 num 类型的特殊扩展,num 本身也是实现了 Comparable,所以原来扩展的方法也都能用。
- max/min/maxOrNull/minOrNull:如果有一个值是
double.nan
,结果就是 NaN - sum:求和,集合为空,返回 0,如果有一个值是
double.nan
,结果就是 NaN - average:求平均值,集合为空,抛出异常,如果有一个值是
double.nan
,结果就是 NaN。除了 average 是 double 类型其它都是 num 类型
IterableDoubleExtension
和 IterableIntegerExtension
相当于 IterableComparableExtension
的特殊情况,就是这些扩展属性的类型不一样,average 都是 double 类型,别的属性分别是 num、double、int 类型。
IterableIterableExtension
extension IterableIterableExtension<T> on Iterable<Iterable<T>>
- flattened:展开打开到一个集合
Iterable<Iterable<int>> iterable = {[1,3,5], {2,4,6}};
print(iterable.flattened); // (1, 3, 5, 2, 4, 6)
IterableNullableExtension
extension IterableNullableExtension<T extends Object> on Iterable<T?>
whereNotNull()
:过滤掉 null 值
print({1,2,null,5,6}.whereNotNull()); // (1, 2, 5, 6)
ListExtensions
extension ListExtensions<E> on List<E>
和 IterableExtension 的同名方法,只是实现有所不同:
forEachIndexed()
forEachWhile()
forEachIndexedWhile()
mapIndexed()
whereIndexed()
whereNotIndexed()
expandIndexed()
elementAtOrNull()
slices()
二分查找:
binarySearch(E element, int compare(E, E)) → int
:列表要符合第二个比较器的排序,二分查找索引binarySearchByCompare<K>(E element, K keyOf(E element), int compare(K, K), [int start = 0, int? end]) → int
:列表元素经过 keyOf 转换后符合第三个参数比较器的排序,然后二分查找索引,start 和 end(不包含) 意思就是要找的元素得在这两个索引之间,如果不在返回 -1binarySearchBy<K extends Comparable<K>>(E element, K keyOf(E element), [int start = 0, int? end]) → int
:和 binarySearchByCompare 对比就是不用参数传递比较器,用默认的a.compareTo(b)
lowerBound(E element, int compare(E, E)) → int
:类似 binarySearch,如果元素在列表中存在,返回位置,如果不存在,返回它应该插入的位置。也是用二分查找lowerBoundByCompare<K>(E element, K keyOf(E), int compare(K, K), [int start = 0, int? end]) → int
:和 lowerBound 的关系类似 binarySearchByCompare 和 binarySearch 的关系,也是用 keyOf 转换后要符合 compare 的关系lowerBoundBy<K extends Comparable<K>>(E element, K keyOf(E), [int start = 0, int? end]) → int
:和 lowerBoundByCompare 的关系类似 binarySearchBy 和 binarySearchByCompare 的关系
List<int> list = [1,3,6,7];
// 第二个参数指定的关系是从小到大
list.binarySearch(3, (a,b)=>a-b); // 1
list.binarySearchByCompare(6, (e)=>10-e, (a,b)=>b-a); // 2
list.binarySearchByCompare(6, (e)=>10-e, (a,b)=>b-a, 0, 2); // -1
list.lowerBound(4, (a,b)=>a-b); // 2
排序:
sortByCompare<K>(K keyOf(E element), int compare(K a, K b), [int start = 0, int? end]) → void
:和 IterableExtension 的 sortedByCompare 对比,就是底层用快速排序,并且多了 start/end 参数sortBy<K extends Comparable<K>>(K keyOf(E element), [int start = 0, int? end]) → void
:和 IterableExtension 的 sortedBy 对比,就是底层用快速排序,并且多了 start/end 参数sortRange(int start, int end, int compare(E a, E b)) → void
:使用快速排序对指定索引范围内的元素进行排序shuffleRange(int start, int end, [Random? random]) → void
:指定范围内随机排序reverseRange(int start, int end) → void
:对指定范围内逆序
List<int> list = [1,3,2,9,5,7,0];
list.sortRange(1, 5, (a,b)=>a-b); // [1, 2, 3, 5, 9, 7, 0]
list.shuffleRange(1, 5);
list.reverseRange(1, 5); // [1, 5, 9, 2, 3, 7, 0],3,2,9,5 倒转顺序
swap(int index1, int index2) → void
:交换两个元素slice(int start, [int? end]) → ListSlice<E>
:切片,就是取子集equals(List<E> other, [Equality<E> equality = const DefaultEquality()]) → bool
:和另一个集合判断是否相等,和ListEquality().equals(a,b)
效果一样
list.slice(1,5); // [3, 2, 9, 5]
ListComparableExtensions
extension ListComparableExtensions<E extends Comparable<E>> on List<E>
是 ListExtensions 的特殊版本,用于元素实现了 Comparable 的 List。
binarySearch()
、lowerBound()
、sortRange()
三个特殊方法,和 ListExtensions 的同名方法的区别就是因为元素是 Comparable 的,不需要一定要传一个比较器,可以使用默认的。