首页 > 其他分享 >Flutter/Dart第03天:Dart可迭代集合

Flutter/Dart第03天:Dart可迭代集合

时间:2023-09-28 20:35:45浏览次数:42  
标签:03 final 元素 alist element 集合 Dart Flutter first

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
}

有趣的结论:

  1. 针对空集合,any()和every()这2个集合条件检测方法,不会抛出异常!
  2. 针对空集合,any()不论断言结果如何,返回值均为false(这个结果比较容易理解)
  3. 针对空集合,every()不论断言结果如何,返回值均为true(这个结果有的奇怪!)

我们打开源代码,看看any()和every()的发现:any()的默认返回值为false,every()的默认返回值true

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;
  }
}

where()/takeWhile()/skipWhile()筛选子集合

上面的any()/every()只是一个条件判断,本节来看看,通过条件来筛选子集合:

  • where()方法:遍历集合每个元素,返回所有符合条件的子集合;若所有元素均不符合条件,则返回空集合,而不是抛出异常!
  • takeWhile()方法:遍历集合元素,构成新子集合元素,直到不符合条件的元素为止。
  • skipWhile()方法:与takeWhile()相反,遍历集合元素,过滤掉前面所有符合条件元素,取结合后面元素。
void main() {
  final List<int> alist = [1, 2, 3];
  
  // 2.5. where()/takeWhile()/skipWhile()筛选子集合
  final gtOneList = alist.where((element) => element > 1);
  print('2.5. where()-筛选子集合: gtOneList=$gtOneList');

  // 结果:2.5. where()-筛选子集合: gtOneList=(2, 3)

  final takeLtThreeList = alist.takeWhile((element) => element < 3);
  print('2.5. takeWhile()-筛选子集合: takeLtTwoList=$takeLtThreeList');

  // 结果:2.5. takeWhile()-筛选子集合: takeLtTwoList=(1, 2)

  final skipNeqTwoList = alist.skipWhile((element) => element != 2);
  print('2.5. skipWhile()-筛选子集合: skipNeqTwoList=$skipNeqTwoList');

  // 结果:2.5. skipWhile()-筛选子集合: skipNeqTwoList=(2, 3)
}

map()转换集合元素

对集合的每个元素,通过map()函数进行一次计算,可把一个结合转换为另一个元素的集合。

void main() {
  final List<int> alist = [1, 2, 3];

  // 2.6. map()转换集合元素
  final alistPlus3 = alist.map((e) => 3 + e);
  print('2.6. map()转换集合元素: $alist -> $alistPlus3');

  // 结果:2.6. map()转换集合元素: [1, 2, 3] -> (4, 5, 6)

  final intToStringList = alist.map((e) => 'value:$e');
  print('2.6. map()转换集合元素: $alist -> $intToStringList');

  // 结果:2.6. map()转换集合元素: [1, 2, 3] -> (value:1, value:2, value:3)
}

最后总结

特别注意:

  1. first/last/firstWhere()这些返回值为单个元素方法,当为空集合或者无法找到元素时,会抛出异常。
  2. where()/takeWhile()/skipWhile()这些返回值为集合的方法,当为空集合或者无法匹配到元素,返回空集合,不会抛出异常。
  3. any()默认返回值为false,every()默认返回值为true

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


标签:03,final,元素,alist,element,集合,Dart,Flutter,first
From: https://www.cnblogs.com/obullxl/p/NTopic2023092701.html

相关文章

  • Flutter开发中的一些Tips
    学习Flutter也有一阵子了。闲着没事,用了公司一个已经凉凉的App设计图来练手。当然了接口不可能用的了,所以都是些死数据,实现效果可以说是很完美了(得到了设计的认可。。。)。当然自己也是边查边写,也借鉴了许多Github上优秀的Flutter项目。现在开源出来(附带设计图),供大家交流学习。希望......
  • 在Flutter中制作指纹认证应用程序
    本文主要展示如何在Flutter中为android应用程序实现指纹认证系统现在许多手机都配备了指纹传感器,这使得用户登录和本地身份验证更容易,而且比使用密码更安全。设置我们的项目在我们开始编写应用程序之前,我们需要先设置一些东西。我们需要做的第一件事是在我们的pubspec.yaml文......
  • from scipy.spatial import ConvexHull, QhullError ImportError: cannot import name
    fromscipy.spatialimportConvexHull,QhullErrorImportError:cannotimportname'QhullError'from'scipy.spatial'(/home/linux/.conda/envs/opencv/lib/python3.8/site-packages/scipy/spatial/__init__.py) 这个错误可能是由于你的 scipy 版本过低导致的。请尝试......
  • string_list_map_date_dart
    title:DartString、List、Map、Date常用方法小结tags:[Flutter,Dart,常用方法小结]categories:常用方法keywords:常用方法小结,string,list,map,date,dartdescription:dart常用方法小结hot:truedate:2020-08-1315:08:00{%noteinfono-icon%}  今日心情......
  • false == ''在js中为何判断为true
    当用==操作符将false对象和其他对象进行比较的时候只有0和空字符串、空数组等于false;undefined和null对象并不等于false对象,而null和undefined是相等的。letcompleted=false;console.log(completed==0);console.log(completed=='');console.log(completed......
  • ERROR: cannot verify github.com's certificate
    wget获取https资源-simplelovecs-博客园(cnblogs.com)加参数>wget--no-check-certificateyour-download-url......
  • Flutter:桌面应用程序开发的新格局
    桌面应用开发的现状在过去,桌面应用程序的开发通常需要使用特定于操作系统的工具和语言,如C++、C#、Java等。这导致了高昂的开发成本和维护困难。尽管有一些跨平台桌面开发工具,如Electron和Qt,但它们在性能、用户体验和开发效率方面存在一些限制。Flutter的出现改变了这一格局,为桌面应......
  • python解决ModuleNotFoundError No module named 'HTMLTestRunner'问题修改
    1、报错截图2、解决方法:(1)py2:从http://tungwaiyip.info/software/HTMLTestRunner.html下载HTMLTestRunner.py并将文件放到python2安装目录的Lib下,然后再次运行文件,可成功运行! (2) py3:a: 从http://tungwaiyip.info/software/HTMLTestRunner.html下载HTMLTestRunner.py......
  • 03_如何仅用递归函数和栈操作逆序一个栈
    如何仅用递归函数和栈操作逆序一个栈【题目】一个栈依次压入1、2、3、4、5,那么从栈顶到栈底分别为5、4、3、2、1。将这个栈转置后,从栈顶到栈底为1、2、3、4、5,也就是实现栈中元素的逆序,但是只能用递归函数来实现,不能用其他数据结构。【解答】本题考察栈的操作和递归函数......
  • CF1020 Codeforces Round 503 (by SIS, Div. 2)
    CF1020ANewBuildingforSIS分类讨论\(a,b\)两个端点的几种情况就好了,特判\(t_a=t_b\)的情况。#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>usingnamespacestd;intn,h,a,b,k;voidsolve(){ intta,fa,tb,fb; scanf(&qu......