可迭代的集合
一些基础知识
- 与java类似,dart也支持List(有序可重复),set(无序不可重复)和map(双列集合).
Iterable类是集合的父类,List和set都是Iterable.例如如下代码片段:
Iterable<int> iterable = [1, 2, 3];//[1, 2, 3]表示一个List
- dart中List支持下标式引用,而Iterable不支持,如下:
var list = [1, 2, 3];
int a = list[0];//正确
Iterable<int> iterable = [1, 2, 3];
int value = iterable[1];//错误
- 作为替代,Iterable支持使用elementAt()方法来获取元素,如下:
Iterable<int> iterable = [1, 2, 3];
int value = iterable.elementAt(1);
Iterable读取元素:
- 使用for-in循环
void main() {
var iterable = ['Salad', 'Popcorn', 'Toast'];
for (var element in iterable) {
print(element);
}
}
- 使用first()(获取第一个元素)和last()(获取最后一个元素):
void main() {
Iterable iterable = ['Salad', 'Popcorn', 'Toast'];
print('The first element is ${iterable.first}');
print('The last element is ${iterable.last}');
}/*~~Console
The first element is Salad
The last element is Toast
*/
- 使用firstWhere()查找第一个符合条件的元素(如果找到则返回该元素,如果未找到或者集合是无穷大则抛一个异常StateError):
bool predicate(String element) {
return element.length > 5;
}
main() {
var items = ['Salad', 'Popcorn', 'Toast', 'Lasagne'];
// You can find with a simple expression:
var element1 = items.firstWhere((element) => element.length > 5);//第一种传参方式:用=>来传入一个单行函数
print(element1);
// Or try using a function block:
var element2 = items.firstWhere((e) {//第二种传参方式:用花括号来传入一个返回判断条件的方法体
return e.length > 5;
});
print(element2);
// Or even pass in a function reference:
var element3 = items.firstWhere(predicate);//第三种传参方式:传入一个现成的外部方法,这个方法需要返回一个布尔类型的值
print(element3);
// You can also use an `orElse` function in case no value is found!
var element4 = items.firstWhere(
(element) => element.length > 10,
orElse: () => 'None!',
);
print(element4);
}/*~~ 结果
Popcorn
Popcorn
Popcorn
None!
*/
从上面这个例子可以看出firstWhere()方法三种传参方式,上面代码中注释中已经较详细了,此处不再赘述 .
- 另一个与firstWhere()功能类似的方法是singleWhere().这个方法用来寻找集合中有且仅有一个的元素,用法如下:
// with the following conditions
// * The element contains the character `'a'`
// * The element starts with the character `'M'`
String singleWhere(Iterable<String> items) {
return items.singleWhere((e) {
return e.startsWith('M') && e.contains('a');//用来返回以'M'开头且含有'a'的元素
});
}
需要注意的是,如果找不到满足条件的元素会抛出一个StateError exception.
判断集合中的元素是否符合某些条件:
java中的常见做法如下:
for (var item in items) {
if (item.length < 5) {
return false;
}
}
return true;//代码复杂冗长,可读性低
dart中以上代码可以用dart中集合的every()方法写成一行:
return items.every((element) => element.length >= 5);//简洁,可读性强
过滤元素
- 之前学过的firstWhere() 和 singleWhere()能帮我们找道符合某些条件的某个元素,但是如果我们想找符合条件的所有元素呢?这时需要用到dart的另一个方法:where()
var evenNumbers = numbers.where((number) => number.isEven);
上面的代码会返回一个包含了numbers中所有的偶数的Iterable.
需要注意的是如果where()方法没有找到符合条件的元素则会返回一个空的Iterable,而不会抛出StateError异常
2. 使用takeWhile()和skipWhile()
- takeWhile(判断条件):一直取知道遇到符合条件的元素
- skipWhile(判断条件):一直跳过知道遇到符合条件的元素才开始取
示例代码:
main() {
var numbers = [1, 3, -2, 0, 4, 5];
var numbersUntilZero = numbers.takeWhile((number) => number != 0);
print('Numbers until 0: $numbersUntilZero');
var numbersAfterZero = numbers.skipWhile((number) => number != 0);
print('Numbers after 0: $numbersAfterZero');
}/*~~Console
Numbers until 0: (1, 3, -2)
Numbers after 0: (0, 4, 5)
*/
Mapping
可以使用map()方法对Iterables进行映射,通过map()可以将Iterables中的元素转换成同种类型的不同值示例如下:
Iterable<int> output = numbers.map((number) => number * 10);//将Iterables中每个值乘以10
更酷炫的是可以转换成不同类型的值:
Iterable<String> output = numbers.map((number) => number.toString());//将Iterables中的int转换成String