dart collection 库

2024-08-27 17:56:19 浏览数 (2)

在看 Flutter 官方的 Flutter Widget of the Week 系列视频时,有一个视频讲 collection 库提供了许多方便的功能,值的从头到晚看一下,网上没搜到什么资料,于是便看下它的 API,试用了一遍。

作为 Dart 官方的库,主要是提供一些操作集合的方法。总体分为三类:封装的类,扩展的方法,顶层的函数。下面先看封装的类。

Delegating

DelegatingIterableDelegatingListDelegatingSetDelegatingMapDelegatingQueue

参数是原始类型的值,有什么用处呢,比如 DelegatingIterable

一来可以扩展它,添加了自定义的操作,原来 Iterable 的操作也可以继续用,并且不直接扩展 Iterable,这样普通的 Iterable 没有这些扩展方法,必须是 DelegatingXXX 类型的才可以用这个扩展方法。

二来假如别的地方扩展了 Iterable 了,但是我现在一些地方不想用,用 DelegatingXXX 后,就只能用属于 Iterable 的方法,而用不了别人扩展 Iterable 的方法。

Combined

CombinedIterableView

将多个集合合并成一个,元素类型可以都不一样。

代码语言:dart复制
CombinedIterableView civ = const CombinedIterableView([{1,2,3},['a','b','c']]);  
print(civ); // (1, 2, 3, a, b, c)

CombinedListView

将多个列表合并成一个列表,元素类型必须一样。

代码语言:dart复制
CombinedListView clv = CombinedListView<int>([[1, 2, 3], [5,6,7]]);  
print(clv); // [1, 2, 3, 5, 6, 7]

CombinedMapView

将多个 Map 合并成一个。

代码语言:dart复制
var map1 = {'a':1,'b':2};  
var map2 = {'cd':3, 'de':4, 'fg': 5};  
var set = {map1, map2};  
CombinedMapView cmv = CombinedMapView(set);  
assert(cmv.length == 5);  
assert(cmv['cd'] == 3);

Equality

CaseInsensitiveEquality

忽略大小写,判断两个字符串是否相同。

代码语言:dart复制
CaseInsensitiveEquality equality = const CaseInsensitiveEquality();  
bool equal = equality.equals('abc', 'ABC');  
assert(equal);

DeepCollectionEquality

如果是集合,递归往里面去对比。

代码语言:dart复制
// 两个不同的内存地址  
var list1 = [2];  
var list2 = [2];  
assert(list1 != list2);  
  
DeepCollectionEquality dce = const DeepCollectionEquality();  
bool equal = dce.equals(list1, list2); // true,比较里面的元素

DefaultEquality

使用参数对象的 == 和 hashcode 来判断。就类似 Java 中重写类的 equals/hashCode 方法后调用 equals 判断两个对象是否相等。

EqualityBy

每个元素使用构造方法的函数参数的返回值来判断是否相等。

代码语言:dart复制
EqualityBy<String, int> eb = EqualityBy((String e)=>e.length);  
bool equal = eb.equals('abc', 'def');  
assert(equal); // 长度相同,所以是 ture

IdentityEquality

Dart 对象都有一个 identity,底层 identical() 方法判断两个 identity 是否相等,其实就是判断引用是否一样。

IterableEquality/ListEquality/SetEquality/MapEquality

对于集合,相同位置的元素相同为 true。如果 Map,就是键值都相等。

MultiEquality

代码语言:dart复制
@override  
bool equals(E e1, E e2) {  
  for (var eq in _equalities) {  
    if (eq.isValidKey(e1)) return eq.isValidKey(e2) && eq.equals(e1, e2);  
  }  
  return false;  
}

参数是其它比较器的列表,然后调用 equals,开始遍历这些比较器,只要一个比较器第一个参数通过 isValidKey 判断为 true 时,就用这个比较器了,第二个参数判断是否有效和 equals 作与。

怎么用,可能要自定义子类,修改 isValidKey 的实现。

代码语言:dart复制
var equalities = [ // 范型要一样  
  const DefaultEquality<String>(),  
  const IdentityEquality<String>(),  
  const CaseInsensitiveEquality(),  
];  
  
MultiEquality me = MultiEquality(equalities);  
bool b = me.equals('abc', 'ABC'); // false

Unmodifiable

UnmodifiableListView

不可变 List,但原始 List 可以变,由于同一个引用,原始的变了,它也变了。

代码语言:dart复制
final numbers = <int>[10, 20, 30];  
final unmodifiableListView = UnmodifiableListView(numbers);  
numbers.addAll([40, 50]);  
print(numbers);  
print(unmodifiableListView); // [10,20,30,40,50]
unmodifiableListView.add(60); // 报错

UnmodifiableSetMixin/UnmodifiableSetView

不可以修改内容的 Set,UnmodifiableSetView 混入了 UnmodifiableSetMixin,UnmodifiableSetMixin 适合其它的 Set,不想让它可变的情况。

代码语言:dart复制
final numbers = <int>{10, 20, 30};  
final unmodifiableSetView = UnmodifiableSetView(numbers);  
numbers.addAll([40, 50]);  
print(numbers); // [10,20,30,40,50]  
print(unmodifiableSetView); // [10,20,30,40,50]  
unmodifiableSetView.add(60); // 报错

UnmodifiableMapView

不可以改变元素的 Map。

代码语言:dart复制
final map = {'a':1, 'b':2};  
final unmodifiableMapView = UnmodifiableMapView(map);  
map['c'] = 3;  
print(unmodifiableMapView); // {a: 1, b: 2, c: 3}  
unmodifiableMapView['d'] = 4; // 报错

UnmodifiableMapMixin

不是 mixin,是 abstract class,UnmodifiableMapView 并不是它的子类。其它 Map 不允许修改的时候继承它。

Map

CanonicalizedMap

将键用一个函数转换。

代码语言:dart复制
// 键长度大于 2 的情况下,变成大写作为键 
CanonicalizedMap<String, String, int> c = CanonicalizedMap((String key)=>key.toUpperCase(), isValidKey: (String key)=>key.length>2);  
c['a'] = 1; // 长度小于 2,不会被插入  
c['cde'] = 2; // 键变成了 CDE
c['cDE'] = 4; // CDE 这个键的值变成了 4
assert(c['CDE']==4);  
  
CanonicalizedMap<String, String, int> c2 = CanonicalizedMap.from({  
  'a': 1,  
  'cde': 2,  
  'cDE': 4  
}, (String key)=>key.toUpperCase());  
assert(c2.length==2);

EqualityMap/EqualitySet

键的相等性由参数的 Equality 对象的 equals 判断

代码语言:dart复制
EqualityMap map = EqualityMap(const CaseInsensitiveEquality());

EqualitySet set = EqualitySet(EqualityBy<String, String>((String e)=>e.toUpperCase()));

MapKeySet

把一个 Map 的所有键拿出来放到一个 Set 里。没看出来有什么用处,因为 keys.toSet 结果都一样的。

代码语言:dart复制
var map = {'b':1, 'a':2, 'bd': 3, 'ae': 4};  
map.keys.toSet();  
bool b = const SetEquality().equals(map.keys.toSet(), MapKeySet(map));  
assert(b);

List

BoolList

值都是布尔值,底层用 Uint32List 存储,节约空间。

代码语言:dart复制
// growable true 表示长度自动增长
factory BoolList(int length, {bool fill = false, bool growable = false})

IterableZip

和 Kotlin 类似。

代码语言:dart复制
IterableZip iz = IterableZip({[1,2], {'a','b','c'},[true, false, true, false]});  
print(iz); // ([1, a, true], [2, b, false])

ListSlice

列表切片,有点类似 Swift 中的字符串切片,和原来的列表共享内存,要变成独立的调用 toList()

在使用列表切片时,源列表不得更改长度。,内部有判断这个,如果不一样,操作会报错。

代码语言:dart复制
var list = ['a','b','c','d','e','f','g'];  
ListSlice<String> slice = ListSlice<String>(list, 2, 5); // [c,d,e],含头不含尾  
assert(slice[0]=='c');  
slice[0]='h'; // list[2] 变成了 h
// 内部调用 source.setRange(start   start, start   end, iterable, skipCount);
// 一个奇怪的算法,参数 1,3,就是修改原 List 的 1 1 到 1 3
slice.setRange(1, 3, ['j','k','l','m']);  
// slice.insert(5, 'f2h'); // 插入会修改长度,报错

NonGrowableListMixin/NonGrowableListView

从一个 List 搞一个长度不可修改的副本。

代码语言:dart复制
var list = [1,2,3,4];  
NonGrowableListMixin nglm = NonGrowableListView(list);
// 内容可以修改,但长度不能修改
nglm[1]=5;

NonGrowableListView 混入了 NonGrowableListMixin 的类,所以要创建 List 用这个功能,就直接用 NonGrowableListView。如果有其它的 List 子类,想让它长度不可变,就自己 with NonGrowableListMixin。

Set

UnionSet

和 set.union() 没什么差别,所以作用不大。混入了 UnmodifiableSetMixin,所以不能修改值。

代码语言:dart复制
var set1 = {1,2,3};  
var set2 = {2,3,4};  
bool equal = const SetEquality().equals(set1.union(set2), UnionSet({set1, set2}));  
assert(equal);

UnionSetController

内部封装了 UnionSet,UnionSet 不可修改,所以合并后就不能再添加新的 Set 去合并,不能删除之前的一个 Set,而 UnionSetController 可以合并后再添加 Set,也可以从合并的结果中删除一个 Set。

代码语言:dart复制
var usc = UnionSetController();  
usc.add(set1);  
usc.add(set2);  
usc.remove(set1);  

PriorityQueue/HeapPriorityQueue

优先队列,优先级越高,越在前面,也是变相实现了排序。

代码语言:dart复制
PriorityQueue pq = PriorityQueue<String>((a,b)=>b.length-a.length);  
hpq.add('abc'); 
hpq.add('ab');  
print(hpq.first);

HeapPriorityQueue 是 PriorityQueue 的子类,基于堆内存,改进了时间复杂度。

代码语言:dart复制
HeapPriorityQueue hpq = HeapPriorityQueue<String>((a,b)=>b.length-a.length);  
hpq.add('abc'); // 时间复杂度是 O(log(n))
hpq.add('a');  
hpq.add('ab');  
print(hpq.first); // abc,时间复杂度 O(1)
print(hpq.toList()); // [abc, ab, a],时间复杂度 O(n*log(n))

QueueList

具有 List 和 Queue 的特性,就是 List 的基础上加上 addFirst/addLast/removeFirst/removeLast 的方法。

代码语言:dart复制
QueueList<String> ql = QueueList(3); // 初始长度  
ql.add('a');  
ql.addFirst('b');  
print(ql);  
QueueList<int> ql2 = QueueList.from([1,2,3,4]);  
ql2.addLast(5);  
ql2.removeFirst();  
print(ql2);

0 人点赞