dart collection 库(2)

2024-08-29 13:32:46 浏览数 (2)

接上篇 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>:就是先将集合中的元素用参数的这个转换函数转换了,然后再用原来的比较器去比较转换后的值
代码语言:dart复制
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 是过滤符合条件的集合,这个是过滤符合条件的第一个,如果没有返回 null
  • firstWhereIndexedOrNull(bool test(int index, T element)) → T?:就是在 firstWhereOrNull 基础上多一个 index
  • lastWhereOrNull(bool test(T element)) → T?:和 firstWhereOrNull 类似,只不过它返回符合过滤条件的最后一个
  • lastWhereIndexedOrNull(bool test(int index, T element)) → T?:就是在 lastWhereOrNull 基础上多一个 index
  • singleWhereOrNull(bool test(T element)) → T?:寻找唯一的元素返回,如果集合空,没找到或者不止一个,就返回 null
  • singleWhereIndexedOrNull(bool test(int index, T element)) → T?:在 singleWhereOrNull 的基础上多一个 index
  • none(bool test(T)) → bool:没有满足条件的元素时返回 true
代码语言:dart复制
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:顺序是否符合先用转换函数转换,再用自定义的排序器排序的结果
代码语言:dart复制
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 返回 false
  • forEachIndexedWhile(bool action(int index, T element)) → void:在 forEachWhile 的基础上带 index
  • mapIndexed<R>(R convert(int index, T element)) → Iterable<R>:在 map() 函数的基础上带 index
代码语言:dart复制
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 开始
代码语言:dart复制
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 组合
代码语言:dart复制
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>>:指定长度分割切片
代码语言:dart复制
// 分块,参数的函数为 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 类型

IterableDoubleExtensionIterableIntegerExtension 相当于 IterableComparableExtension 的特殊情况,就是这些扩展属性的类型不一样,average 都是 double 类型,别的属性分别是 num、double、int 类型。

IterableIterableExtension

extension IterableIterableExtension<T> on Iterable<Iterable<T>>

  • flattened:展开打开到一个集合
代码语言:dart复制
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 值
代码语言:dart复制
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(不包含) 意思就是要找的元素得在这两个索引之间,如果不在返回 -1
  • binarySearchBy<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 的关系
代码语言:dart复制
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:对指定范围内逆序
代码语言:dart复制
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) 效果一样
代码语言:dart复制
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 的,不需要一定要传一个比较器,可以使用默认的。

0 人点赞