Dart官网代码实验室:https://dart.dev/codelabs/iterables
重要说明:本博客基于Dart官网代码实验室,但并不是简单的对官网文章进行翻译,我会根据个人研发经验,在覆盖官网文章核心内容情况下,加入自己的一些扩展问题和问题演示和总结,包括名称解释、使用场景说明、代码样例覆盖等。
可迭代集合说明
什么是集合?集合代表一组对象的组合,集合中的对象一般称为元素,元素的数量可以是0个(即空集合),也可以有多个。
什么是迭代?迭代即顺序访问,即这个集合中的元素可从头到尾进行顺序访问(一般在循环遍历中使用)。在Java中,我们知道有个Iterable迭代类,在Dart中也有这个类(https://api.dart.dev/stable/3.1.3/dart-core/Iterable-class.html),我们用的最多的就是List和Set接口,他们是迭代集合的基础,也是一个应用程序的基础。
Map是可迭代集合吗?Map类代表了一组元素,因此它是一个集合。但Map类没有实现Iterable类(https://api.dart.dev/stable/3.1.3/dart-core/Map-class.html),因此它不可迭代,也就是说:Map是不可迭代的集合。但是它的元素集合(Map#entries)、键集合(Map#keys)和值集合(Map#values)都是可迭代集合。
迭代和集合访问元素的不同方式:迭代通过elementAt(index)方法访问元素,而集合可以通过[index]下标的方法访问元素:- void main() {
- // 1. 迭代和集合访问元素
- final List<int> alist = [1, 2, 3];
- final Iterable<int> iterable = alist;
- print('1. 迭代和集合访问元素: ${iterable.elementAt(2)} <-> ${alist[2]}');
-
- // 结果:1. 迭代和集合访问元素: 3 <-> 3
- }
复制代码 可迭代集合元素访问方法
可迭代集合元素的访问方式有很多种,包括for循环,集合的第1个元素,集合的最后1个元素,寻找符合条件的第1个元素等。
for-in循环访问集合元素
这种方式使用最多了,各种编程语言基本类似:- void main() {
- final List<int> alist = [1, 2, 3];
-
- // 2.1. for循环访问集合元素
- for (final element in alist) {
- print('2.1. for循环访问集合元素: $element');
- }
-
- // 结果:
- // 2.1. for循环访问集合元素: 1
- // 2.1. for循环访问集合元素: 2
- // 2.1. for循环访问集合元素: 3
- }
复制代码 first第一个和last最后一个元素:空集合异常
通过first和last属性,可直接访问集合的第1个和最后1个元素:- void main() {
- final List<int> alist = [1, 2, 3];
- // 2.2 first第一个和last最后一个元素
- print('2.2. first第一个和last最后一个元素: first=${alist.first}, last=${alist.last}');
-
- // 结果:2.2. first第一个和last最后一个元素: first=1, last=3
- }
复制代码 扩展问题:如果集合只有1个元素,或者集合是空集合,first和last返回的内容是什么呢?- void main() {
- final List<int> oneList = [1];
- print('2.2. first第一个和last最后一个元素: one.first=${oneList.first}, one.last=${oneList.last}');
-
- // 结果:2.2. first第一个和last最后一个元素: one.first=1, one.last=1
-
- final List<int> emptyList = [];
- print('2.2. first第一个和last最后一个元素: empty.first=${emptyList.first}, empty.last=${emptyList.last}');
-
- // 结果:Bad state: No element
- }
- // 异常如下:
- Unhandled exception:
- Bad state: No element
- #0 List.first (dart:core-patch/growable_array.dart:343:5)
复制代码 结论:只有1个元素的集合,first和last返回值相同,均为唯一的那个元素;对于空集合,first或者last均抛出异常!
firstWhere()/orElse符合条件的第1个元素
断言:一个返回true/false的表达式、方法或者代码块。firstWhere()的本质就是遍历集合,对每个元素进行断言,然后返回第一个断言为true的元素。- void main() {
- final List<int> alist = [1, 2, 3];
- // 2.3. firstWhere()符合条件的第1个元素
- final int firstWhere = alist.firstWhere((element) => element > 1);
- print('2.3. firstWhere()符合条件的第1个元素: $firstWhere');
- // 结果:2.3. firstWhere()符合条件的第1个元素: 2
- }
复制代码 扩展问题:如果过滤条件均不满足(即每个元素断言均返回false),则返回结果是什么呢?- void main() {
- final List<int> alist = [1, 2, 3];
- // 2.3. firstWhere()符合条件的第1个元素
- final int firstWhere2 = alist.firstWhere((element) => element > 3);
- print('2.3. firstWhere()符合条件的第1个元素2: $firstWhere2');
- // 结果:Bad state: No element
- }
- // 异常如下:
- Unhandled exception:
- Bad state: No element
- #0 ListBase.firstWhere (dart:collection/list.dart:132:5)
复制代码 结论:和空集合一样,当firstWhere()无法匹配到任何元素时,会抛出异常!
那么,当无法匹配到任何元素时,有没有办法不抛出异常,而是返回一个默认值呢?
答案是有的:firstWhere()断言之后,增加orElse默认值的命名参数,它是一个函数!- void main() {
- final List<int> alist = [1, 2, 3];
- // 2.3. firstWhere()符合条件的第1个元素
- final int firstWhere2 = alist.firstWhere(
- (element) => element > 3,
- orElse: () => -1,
- );
- print('2.3. firstWhere()符合条件的第1个元素2: $firstWhere2');
- // 结果:2.3. firstWhere()符合条件的第1个元素2: -1
- }
复制代码 any()/every()集合检测(有趣的结果和源代码)
当我们需要检测集合中是否存在符合某个条件的元素,或者所有元素是否符合某个条件。在Dart语言中,我们可以使用any()和every()这两个集合条件检测方法,来达到我们的目的。
- any()方法:集合中存在任一一个元素符合条件
- every()方法:集合中的所有元素均符合条件
- void main() {
- final List<int> alist = [1, 2, 3];
- // 2.4. any()/every()集合条件检测
- final bool anyGtTwo = alist.any((element) => element > 2);
- final bool everyGtZero = alist.every((element) => element > 0);
- final bool everyGtTwo = alist.every((element) => element > 2);
- print('2.4. any()/every()集合条件检测: anyGtTwo=$anyGtTwo, everyGtZero=$everyGtZero, everyGtTwo=$everyGtTwo');
- // 结果:2.4. any()/every()集合条件检测: anyGtTwo=true, everyGtZero=true, everyGtTwo=false
- }
复制代码 扩展问题:如果是个空集合,any()和every()的结果如何,会抛出异常吗?- void main() {
- final elist = <int>[];
- final bool anyGtZero = elist.any((element) => element > 0);
- final bool anyLtEqZero = elist.any((element) => element <= 0);
- print('2.4. any()-空集合条件检测: anyGtZero=$anyGtZero, anyLtEqZero=$anyLtEqZero');
- // 结果:2.4. any()-空集合条件检测: anyGtZero=false, anyLtEqZero=false
- final bool evyGtZero = elist.every((element) => element > 0);
- final bool evyLtEqZero = elist.every((element) => element <= 0);
- print('2.4. every()-空集合条件检测: evyGtZero=$evyGtZero, evyLtEqZero=$evyLtEqZero');
- // 结果:2.4. every()-空集合条件检测: evyGtZero=true, evyLtEqZero=true
- }
复制代码 map()转换集合元素
对集合的每个元素,通过map()函数进行一次计算,可把一个结合转换为另一个元素的集合。- abstract mixin class Iterable<E> {
- // 默认返回值:false
- bool any(bool test(E element)) {
- for (E element in this) {
- if (test(element)) return true;
- }
- return false;
- }
- // 默认返回值:true
- bool every(bool test(E element)) {
- for (E element in this) {
- if (!test(element)) return false;
- }
- return true;
- }
- }
复制代码 最后总结
特别注意:
- first/last/firstWhere()这些返回值为单个元素方法,当为空集合或者无法找到元素时,会抛出异常。
- where()/takeWhile()/skipWhile()这些返回值为集合的方法,当为空集合或者无法匹配到元素,返回空集合,不会抛出异常。
- any()默认返回值为false,every()默认返回值为true
我的本博客原地址:https://ntopic.cn/p/2023092701/
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |