ToB企服应用市场:ToB评测及商务社交产业平台

标题: Flutter/Dart第03天:Dart可迭代集合 [打印本页]

作者: 玛卡巴卡的卡巴卡玛    时间: 2023-10-9 13:40
标题: Flutter/Dart第03天:Dart可迭代集合
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]下标的方法访问元素:
  1. void main() {
  2.   // 1. 迭代和集合访问元素
  3.   final List<int> alist = [1, 2, 3];
  4.   final Iterable<int> iterable = alist;
  5.   print('1. 迭代和集合访问元素: ${iterable.elementAt(2)} <-> ${alist[2]}');
  6.   
  7.   // 结果:1. 迭代和集合访问元素: 3 <-> 3
  8. }
复制代码
可迭代集合元素访问方法

可迭代集合元素的访问方式有很多种,包括for循环,集合的第1个元素,集合的最后1个元素,寻找符合条件的第1个元素等。
for-in循环访问集合元素

这种方式使用最多了,各种编程语言基本类似:
  1. void main() {
  2.   final List<int> alist = [1, 2, 3];
  3.   
  4.   // 2.1. for循环访问集合元素
  5.   for (final element in alist) {
  6.     print('2.1. for循环访问集合元素: $element');
  7.   }
  8.   
  9.   // 结果:
  10.   // 2.1. for循环访问集合元素: 1
  11.   // 2.1. for循环访问集合元素: 2
  12.   // 2.1. for循环访问集合元素: 3
  13. }
复制代码
first第一个和last最后一个元素:空集合异常

通过first和last属性,可直接访问集合的第1个和最后1个元素:
  1. void main() {
  2.   final List<int> alist = [1, 2, 3];
  3.   // 2.2 first第一个和last最后一个元素
  4.   print('2.2. first第一个和last最后一个元素: first=${alist.first}, last=${alist.last}');
  5.   
  6.   // 结果:2.2. first第一个和last最后一个元素: first=1, last=3
  7. }
复制代码
扩展问题:如果集合只有1个元素,或者集合是空集合,first和last返回的内容是什么呢?
  1. void main() {
  2.   final List<int> oneList = [1];
  3.   print('2.2. first第一个和last最后一个元素: one.first=${oneList.first}, one.last=${oneList.last}');
  4.   
  5.   // 结果:2.2. first第一个和last最后一个元素: one.first=1, one.last=1
  6.   
  7.   final List<int> emptyList = [];
  8.   print('2.2. first第一个和last最后一个元素: empty.first=${emptyList.first}, empty.last=${emptyList.last}');
  9.   
  10.   // 结果:Bad state: No element
  11. }
  12. // 异常如下:
  13. Unhandled exception:
  14. Bad state: No element
  15. #0      List.first (dart:core-patch/growable_array.dart:343:5)
复制代码
结论:只有1个元素的集合,first和last返回值相同,均为唯一的那个元素;对于空集合,first或者last均抛出异常!
firstWhere()/orElse符合条件的第1个元素

断言:一个返回true/false的表达式、方法或者代码块。firstWhere()的本质就是遍历集合,对每个元素进行断言,然后返回第一个断言为true的元素。
  1. void main() {
  2.   final List<int> alist = [1, 2, 3];
  3.   // 2.3. firstWhere()符合条件的第1个元素
  4.   final int firstWhere = alist.firstWhere((element) => element > 1);
  5.   print('2.3. firstWhere()符合条件的第1个元素: $firstWhere');
  6.   // 结果:2.3. firstWhere()符合条件的第1个元素: 2
  7. }
复制代码
扩展问题:如果过滤条件均不满足(即每个元素断言均返回false),则返回结果是什么呢?
  1. void main() {
  2.   final List<int> alist = [1, 2, 3];
  3.   // 2.3. firstWhere()符合条件的第1个元素
  4.   final int firstWhere2 = alist.firstWhere((element) => element > 3);
  5.   print('2.3. firstWhere()符合条件的第1个元素2: $firstWhere2');
  6.   // 结果:Bad state: No element
  7. }
  8. // 异常如下:
  9. Unhandled exception:
  10. Bad state: No element
  11. #0      ListBase.firstWhere (dart:collection/list.dart:132:5)
复制代码
结论:和空集合一样,当firstWhere()无法匹配到任何元素时,会抛出异常!
那么,当无法匹配到任何元素时,有没有办法不抛出异常,而是返回一个默认值呢?
答案是有的:firstWhere()断言之后,增加orElse默认值的命名参数,它是一个函数!
  1. void main() {
  2.   final List<int> alist = [1, 2, 3];
  3.   // 2.3. firstWhere()符合条件的第1个元素
  4.   final int firstWhere2 = alist.firstWhere(
  5.     (element) => element > 3,
  6.     orElse: () => -1,
  7.   );
  8.   print('2.3. firstWhere()符合条件的第1个元素2: $firstWhere2');
  9.   // 结果:2.3. firstWhere()符合条件的第1个元素2: -1
  10. }
复制代码
any()/every()集合检测(有趣的结果和源代码)

当我们需要检测集合中是否存在符合某个条件的元素,或者所有元素是否符合某个条件。在Dart语言中,我们可以使用any()和every()这两个集合条件检测方法,来达到我们的目的。
  1. void main() {
  2.   final List<int> alist = [1, 2, 3];
  3.   // 2.4. any()/every()集合条件检测
  4.   final bool anyGtTwo = alist.any((element) => element > 2);
  5.   final bool everyGtZero = alist.every((element) => element > 0);
  6.   final bool everyGtTwo = alist.every((element) => element > 2);
  7.   print('2.4. any()/every()集合条件检测: anyGtTwo=$anyGtTwo, everyGtZero=$everyGtZero, everyGtTwo=$everyGtTwo');
  8.   // 结果:2.4. any()/every()集合条件检测: anyGtTwo=true, everyGtZero=true, everyGtTwo=false
  9. }
复制代码
扩展问题:如果是个空集合,any()和every()的结果如何,会抛出异常吗?
  1. void main() {
  2.   final elist = <int>[];
  3.   final bool anyGtZero = elist.any((element) => element > 0);
  4.   final bool anyLtEqZero = elist.any((element) => element <= 0);
  5.   print('2.4. any()-空集合条件检测: anyGtZero=$anyGtZero, anyLtEqZero=$anyLtEqZero');
  6.   // 结果:2.4. any()-空集合条件检测: anyGtZero=false, anyLtEqZero=false
  7.   final bool evyGtZero = elist.every((element) => element > 0);
  8.   final bool evyLtEqZero = elist.every((element) => element <= 0);
  9.   print('2.4. every()-空集合条件检测: evyGtZero=$evyGtZero, evyLtEqZero=$evyLtEqZero');
  10.   // 结果:2.4. every()-空集合条件检测: evyGtZero=true, evyLtEqZero=true
  11. }
复制代码
map()转换集合元素

对集合的每个元素,通过map()函数进行一次计算,可把一个结合转换为另一个元素的集合。
  1. abstract mixin class Iterable<E> {
  2.   // 默认返回值:false
  3.   bool any(bool test(E element)) {
  4.     for (E element in this) {
  5.       if (test(element)) return true;
  6.     }
  7.     return false;
  8.   }
  9.   // 默认返回值:true
  10.   bool every(bool test(E element)) {
  11.     for (E element in this) {
  12.       if (!test(element)) return false;
  13.     }
  14.     return true;
  15.   }
  16. }
复制代码
最后总结

特别注意:
我的本博客原地址:https://ntopic.cn/p/2023092701/

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4