# 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 ```