# Referance
[Iterable](https://api.dart.dev/stable/3.3.3/dart-core/Iterable-class.html)
[Iterator](https://api.dart.dev/stable/3.3.3/dart-core/Iterator-class.html)
[Iterator.moveNext()](https://api.dart.dev/stable/3.3.3/dart-core/Iterator/moveNext.html)
[Iterator.current](https://api.dart.dev/stable/3.3.3/dart-core/Iterator/current.html)
[Iterable collections](https://dart.dev/codelabs/iterables)
# 概論
Iterable是一個可以依序存取元素值的類別
Iterable是抽象類別(不可初始化物件), 以下都是Iterable的實作
[List](https://hackmd.io/@asdf121472/BJW6JQ9xR)
[Set](https://hackmd.io/@asdf121472/SkRQUcfZR)
[Map](https://hackmd.io/@asdf121472/B1VD2D7WR)的keys和values
Iterable主要有三個部分:
1. 使用getter取得Iterator, 使用Iterator可以依序存取集合內的所有元素
2. Iterator.moveNext() 第一次使用時, 指針會指到第一個元素, 並回傳true, 沒有元素時, 會回傳false
3. Iterator.current 回傳指針目前所指的元素
```
Iterable<int> li=[1,2,3];
Iterator<int> it=li.iterator;
while (it.moveNext()){
print(it.current);
// 1
// 2
// 3
}
print(it.moveNext()); // false
// print(it.current); // type 'Null' is not a subtype of type 'int' in type cast
```
# Constructors
#### `Iterable.empty()`
建立一個空的可迭代物件
```
var i = Iterable.empty();
var i2 = i.followedBy([1, 2, 3]);
print(i2); // (1, 2, 3)
```
#### `惰性` `Iterable.generate(int n, [E generator(int index)?])`
依據generator函數, 動態產生n個元素的可迭代物件
```
var i = Iterable.generate(5);
print(i.toString()); // (0, 1, 2, 3, 4)
var i2 = Iterable.generate(5,(index)=>index*index);
print(i2.toString()); // (0, 1, 4, 9, 16)
```
# Properties
#### `iterator → Iterator<E>`
#### `hashCode → int`
#### `first → E`
#### `last → E`
#### `length → int `
#### `runtimeType → Type`
#### `isEmpty → bool`
#### `isNotEmpty → bool`
#### `single → E`
```
if (this.length==1) => this.elementAt(0)
if (this.length>1 || this.length==0) => throw StateError
```
# Methods
## *依條件測試所有元素(=> bool)*
#### `any(bool test(E element)) → bool`
任一元素符合條件
```
final li=[1,2,3,5,6,7];
var res=li.any((element) => element>7);
print(res); // false
res=li.any((element) => element<2);
print(res); // true
```
#### `every(bool test(E element)) → bool`
所有元素符合條件
```
final planetsByMass = <double, String>{
0.06: 'Mercury',
0.81: 'Venus',
0.11: 'Mars'
};
// Checks whether all keys are smaller than 1.
final every = planetsByMass.keys.every((key) => key < 1.0); // true
```
#### `contains(Object? element) → bool`
是否包含`element`元素
```
final gasPlanets = <int, String>{1: 'Jupiter', 2: 'Saturn'};
final containsOne = gasPlanets.keys.contains(1); // true
final containsFive = gasPlanets.keys.contains(5); // false
final containsJupiter = gasPlanets.values.contains('Jupiter'); // true
final containsMercury = gasPlanets.values.contains('Mercury'); // false
```
## *取值*
#### `elementAt(int index) → E`
```
final numbers = <int>[1, 2, 3, 5, 6, 7];
final elementAt = numbers.elementAt(4); // 6
```
#### `firstWhere(bool test(E element), {E orElse()?}) → E`
滿足給定條件 test 的第一個元素。
#### `lastWhere(bool test(E element), {E orElse()?}) → E`
滿足給定條件 test 的最後一個元素。
```
final numbers = <int>[1, 2, 3, 5, 6, 7];
var result = numbers.firstWhere((element) => element < 5); // 1
result = numbers.firstWhere((element) => element > 5); // 6
result =
numbers.firstWhere((element) => element > 10, orElse: () => -1); // -1
```
#### `singleWhere(bool test(E element), {E orElse()?}) → E`
集合中只有一個元素滿足test函數則返回該元素
集合中多個元素滿足test函數則throw [StateError](https://api.dart.dev/stable/3.3.3/dart-core/StateError-class.html)
集合中無元素滿足test函數, 則返回orElse提供的值, 否則throw [StateError](https://api.dart.dev/stable/3.3.3/dart-core/StateError-class.html)
```
// 單一符合
final numbers = <int>[2, 2, 10];
var result = numbers.singleWhere((element) => element > 5); // 10
// 沒有符合
result =
numbers.singleWhere((element) => element == 1, orElse: () => -1); // -1
// 一個以上符合
result = numbers.singleWhere((element) => element == 2); // Throws Error.
```
## *對所有元素做即時運算*
#### `forEach(void action(E element)) → void`
依序對每個元素呼叫action函數, 立刻執行, 無返回值
```
final numbers = <int>[1, 2, 6];
numbers.forEach(print);
// 1
// 2
// 6
```
#### `join([String separator = ""]) → String`
將元素轉換成字串並以separator連接
```
final numbers = <dynamic>[2, true, 'a'];
var join_ = numbers.join('-');
print(join_); // 2-true-a
```
#### `fold<T>(T initialValue, T combine(T previousValue, E element)) → T`
將集合的每個元素與現有值組合,將集合減少為單一值
```
final numbers = <double>[10, 2, 5, 0.5];
const initialValue = 100.0;
final result = numbers.fold<double>(
initialValue, (previousValue, element) => previousValue + element);
print(result); // 117.5
```
#### `reduce(E combine(E value, E element)) → E`
透過使用combine函數迭代組合集合的元素,將集合減少為單一值。
```
final numbers = <double>[10, 2, 5, 0.5];
final result = numbers.reduce((value, element) => value * element);
print(result); // 50.0
```
## *產生新的 Iterable*
返回另一個 Iterable 的方法(如 map 和 where)都是惰性的 - 它們將在每次返回的可迭代物件被迭代時才計算要讀寫的元素
#### `惰性` `map<T>(T toElement(E e)) → Iterable<T>`
返回新的`Iterable<T>`, 迭代時才套用toElement函數產生新的元素
```
final li=[1,2,3];
Iterable<dynamic> lis=li.map(print);
lis.elementAt(2); // 3
```
#### `惰性` `where(bool test(E element)) → Iterable<E>`
返回所有滿足test的元素所組成的新Iterable
```
final numbers = <int>[1, 2, 3, 5, 6, 7];
var result = numbers.where((x) => x < 5); // (1, 2, 3)
result = numbers.where((x) => x.isEven); // (2, 6)
result = numbers.where((x) => x==4); // ()
```
#### `惰性` `whereType<T>() → Iterable<T>`
將集合中所有T類型的元素抽取出來, 組成新的Iterable並返回
```
Iterable<dynamic> mixed = [1, 'two', 3.0, 'four', 5];
Iterable<int> ints=mixed.whereType<int>();
print(ints); // (1,5)
Iterable<String> strs=mixed.whereType<String>();
print(strs); // (two, four)
```
#### `惰性` `followedBy(Iterable<E> other) → Iterable<E>`
建立此可迭代物件和 other 的惰性串聯。
```
var planets = <String>['Earth', 'Jupiter'];
var updated = planets.followedBy(['Mars', 'Venus']);
print(updated); // (Earth, Jupiter, Mars, Venus)
```
#### `惰性` `skip(int n) → Iterable<E>`
跳過前面n個元素, 將剩下的元素組成新的Iterable並返回
```
final numbers = <int>[1, 2, 3, 5, 6, 7];
final result = numbers.skip(4); // (6, 7)
final skipAll = numbers.skip(100); // () - no elements.
final skip0 = numbers.skip(0); // (1, 2, 3, 5, 6, 7)
```
#### `惰性` `skipWhile(bool test(E value)) → Iterable<E>`
滿足test函數的元素都跳過, 直到不滿足時返回剩下的元素組成的Iterable
```
final numbers = <int>[1, 2, 3, 5, 6, 7];
var result = numbers.skipWhile((x) => x < 5); // (5, 6, 7)
result = numbers.skipWhile((x) => x != 3); // (3, 5, 6, 7)
result = numbers.skipWhile((x) => x != 4); // ()
result = numbers.skipWhile((x) => x.isOdd); // (2, 3, 5, 6, 7)
```
#### `惰性` `take(int n) → Iterable<E>`
返回前n個元素組成的新Iterable
```
final numbers = <int>[1, 2, 3, 5, 6, 7];
final result = numbers.take(4); // (1, 2, 3, 5)
final takeAll = numbers.take(100); // (1, 2, 3, 5, 6, 7)
```
#### `惰性` `takeWhile(bool test(E value)) → Iterable<E>`
```
final numbers = <int>[1, 2, 3, 5, 6, 7];
var result = numbers.takeWhile((x) => x < 5); // (1, 2, 3)
result = numbers.takeWhile((x) => x != 3); // (1, 2)
result = numbers.takeWhile((x) => x != 4); // (1, 2, 3, 5, 6, 7)
result = numbers.takeWhile((x) => x.isOdd); // (1)
```
#### `惰性` `expand<T>(Iterable<T> toElements(E element)) → Iterable<T>`
將此 Iterable 的每個元素擴展為零個或多個元素。
```
Iterable<int> count(int n) sync* {
for (var i = 1; i <= n; i++) {
yield i;
}
}
var numbers = [1, 3, 0, 2];
print(numbers.expand(count)); // (1, 1, 2, 3, 1, 2)
```
## *Iterable 轉換成其他類型*
#### `toList({bool growable = true}) → List<E>`
#### `toSet() → Set<E>`
#### `toString() → String`
#### `cast<R>() → Iterable<R>`
Iterable 所有元素轉換成R類型
```
Iterable<dynamic> i = [1, 2, 'a'];
print(i.runtimeType); // _GeneratorIterable<num>
Iterable<int> i2 = i.cast<int>();
print(i2.runtimeType); // _EfficientLengthCastIterable<num, int>
// i2.forEach(print); // type 'String' is not a subtype of type 'int' in type cast
```
# Static Methods
#### `static List<T> castFrom<S, T>(List<S> source) => CastList<S, T>(source);`
將 `List<S> source` 改編為 `Iterable<T>`
```
Iterable i1 =[1,2,'a'];
print(i1.runtimeType); // List<dynamic>
Iterable<int> i2=Iterable.castFrom<dynamic,int>(i1);
print(i2.runtimeType); // _EfficientLengthCastIterable<dynamic, int>
// print(i2.elementAt(2)); // type 'String' is not a subtype of type 'int' in type cast
```
#### `iterableToFullString(Iterable iterable, [String leftDelimiter = '(', String rightDelimiter = ')']) → String`
#### `iterableToShortString(Iterable iterable, [String leftDelimiter = '(', String rightDelimiter = ')']) → String`
```
Iterable i1 =[1,2,'a'];
String s1=Iterable.iterableToFullString(i1,'[',']');
print(s1); // [1, 2, a]
String s2=Iterable.iterableToShortString(i1,'[',']');
print(s2); // [1, 2, a]
String s3=i1.toString();
print(s3); // [1, 2, a]
```
# Operators
#### `operator ==(Object other) → bool`
Iterable物件 只會等於自身
```
Iterable i1=Iterable.generate(10);
Iterable i2=Iterable.generate(10);
Iterable i3=i1;
print(i1==i2); // false
print(identical(i1, i2)); // false
print(i1==i3); // true
print(identical(i1, i3)); // true
```