# [List](https://api.dart.dev/stable/3.3.3/dart-core/List-class.html) [Iterable](https://hackmd.io/@asdf121472/HkXHn-cgR) # 概論 具有長度的可索引物件集合。List實作Iterable ,所以繼承其所有方法,包括 where、map、whereType 和 toList。 常見的List有: * Fixed-length list `List<int>.filled(5, 0)` * Growable list `final growableList = <String>['A', 'B'];` #### [新增資料到List](#新增元素) * `add(E value)` * `addAll(Iterable<E> iterable)` * `insert(int index, E element)` * `insertAll(int index, Iterable<E> iterable)` #### [讀取元素或索引](#讀取元素or索引) * `indexOf(E element, [int start = 0]) → int` * `indexWhere(bool test(E element), [int start = 0]) → int` * `lastIndexOf(E element, [int? start]) → int` * `lastIndexWhere(bool test(E element), [int? start]) → int` #### [List切片](#sublistint-start-int-end-→-ListltEgt) * `getRange(int start, int end) → Iterable<E>` * `sublist(int start, [int? end]) → List<E>` #### [從growable list移除元素](#移除元素) * `clear() → void` * `remove(Object? value) → bool` * `removeAt(int index) → E` * `removeLast() → E` * `removeRange(int start, int end) → void` * `removeWhere(bool test(E element)) → void` * `retainWhere(bool test(E element)) → void` #### [插入元素](#insertint-index-E-element-→-void) * `insert(int index, E element) → void` * `insertAll(int index, Iterable<E> iterable) → void` #### [取代一定範圍的元素](#替代元素) * `fillRange(int start, int end, [E? fillValue]) → void` * `replaceRange(int start, int end, Iterable<E> replacements) → void` * `setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) → void` * `setAll(int index, Iterable<E> iterable) → void` #### [排序或打亂](#排序與打亂) * `sort([int compare(E a, E b)?]) → void` 排序 * `shuffle([Random? random]) → void` 打亂 #### [依條件遍歷元素並返回符合者](https://hackmd.io/@asdf121472/HkXHn-cgR) * `firstWhere()` * `lastWhere()` * `singleWhere()` # Constructors * `List.empty({bool growable = false})` 建立一個空的List物件 * `List.filled(int length, E fill, {bool growable = false})` 建立一個length長度的列表,每個位置都用fill填充 ``` final zeroList = List<int>.filled(3, 0, growable: true); // [0, 0, 0] print(zeroList); // [0, 0, 0] ``` * `List<E>.from(Iterable elements, {bool growable = true})` * `List.of(Iterable<E> elements, {bool growable = true})` [List.from vs List.of](https://stackoverflow.com/questions/50320220/in-dart-whats-the-difference-between-list-from-and-of-and-between-map-from-a) List.from: 所有elements必須是E的實例, 可用來down-cast or up-cast(內部可能使用elements.whereType(E)) ``` // List.from 可以 down-cast or up-cast List<num> numList = [1, 2, 3]; // List<num> var toIntList = List<int>.from(numList); // List<int> var toNumList = List<num>.from(toIntList); // List<num> ``` List.of: 會判斷出正確類型 ``` var iterable = [1, 2, 3]; // List<int> var listFrom = List.from(iterable); // List<dynamic> var listOf=List.of(iterable); // List<int> ``` List.of: 可以 up-cast 不能 down-cast ``` // 可以 up-cast List<int> iterable = [1, 2, 3]; // List<int> var numList = List<num>.of(iterable); // int 可以賦值給 num變數 print(numList.runtimeType); // List<num> // 不能 down-cast List<num> ite = <num>[3.5]; // var doubleList=List<double>.of(ite); // num不能賦值給double變數 ``` 結論: 要做父子類型轉換就用`.from`, 要產生與原來類型一樣的拷貝就用`.of` * `List.generate(int length, E generator(int index), {bool growable = true})` 建立長度是`length`的List, 元素是根據generator函數計算出來的. ``` final fixedLengthList = List<int>.generate(3, (int index) => index * index, growable: false); print(fixedLengthList); // [0, 1, 4] ``` * `List.unmodifiable(Iterable elements)` 建立一個包含所有 elements 的不可修改List # Properties #### `first → E` #### `last → E` #### `length → int` #### `hashCode → int` #### `runtimeType → Type` #### `iterator → Iterator<E>` #### `reversed → Iterable<E>` List中元素的按相反順序排列 #### `isEmpty → bool` #### `isNotEmpty → bool` #### `single → E` ``` if (this.length==1) => this[0] if (this.length>1 || this.length==0) => throw StateError ``` # Methods ([Iterable](https://hackmd.io/@asdf121472/HkXHn-cgR)的方法都可以使用) ## *讀取元素or索引* * #### `indexOf(E element, [int start = 0]) → int` ``` const notes = <String>['do', 're', 'mi', 're']; var index = notes.indexOf('re', 2); // 3 index = notes.indexOf('re'); // 1 index = notes.indexOf('fa'); // -1 沒有找到 ``` * #### `lastIndexOf(E element, [int? start]) → int` 反向搜尋, 搜尋範圍 start 到 0 ``` const notes = <String>['do', 're', 'mi', 're']; var startIndex = 3; var index = notes.lastIndexOf('re', startIndex); // 3 startIndex = 2; index = notes.lastIndexOf('re', startIndex); // 1 index = notes.lastIndexOf('re'); // 3 index = notes.lastIndexOf('fa'); // -1 沒有找到 ``` * #### `indexWhere(bool test(E element), [int start = 0]) → int` ``` final notes = <String>['do', 're', 'mi', 're']; final first = notes.indexWhere((e) => e.startsWith('r')); // 1 final second = notes.indexWhere((e) => e.startsWith('r'), 2); // 3 ``` * #### `lastIndexWhere(bool test(E element), [int? start]) → int` 反向搜尋, 搜尋範圍 start 到 0 ``` final notes = <String>['do', 're', 'mi', 're']; final first = notes.lastIndexWhere((note) => note.startsWith('r')); // 3 final second = notes.lastIndexWhere((note) => note.startsWith('r'), 2); // 1 final index = notes.lastIndexWhere((note) => note.startsWith('k')); // -1 沒有找到 ``` * #### `sublist(int start, [int? end]) → List<E>` ``` final colors = <String>['red', 'green', 'blue', 'orange', 'pink']; print(colors.sublist(1, 3)); // [green, blue] print(colors.sublist(3)); // [orange, pink] ``` * #### `getRange(int start, int end) → Iterable<E>` ``` final colors = <String>['red', 'green', 'blue', 'orange', 'pink']; final subList = colors.getRange(0, 3); print('$subList ${subList.runtimeType}'); // (red, green, blue) SubListIterable<String> ``` ## *新增元素* * #### `add(E value) → void` ``` final numbers = <int>[1, 2, 3]; numbers.add(4); // [1, 2, 3, 4] ``` * #### `addAll(Iterable<E> iterable) → void` ``` final numbers = <int>[1, 2, 3]; numbers.addAll([4, 5, 6]); // [1, 2, 3, 4, 5, 6] ``` * #### `insert(int index, E element) → void` ``` List numbers = [1, 2, 3, 4]; numbers.insert(2, 'a'); print(numbers); // [1, 2, a, 3, 4] ``` * #### `insertAll(int index, Iterable<E> iterable) → void` ``` final numbers = <int>[1, 2, 3, 4]; numbers.insertAll(2, [10, 11]); print(numbers); // [1, 2, 10, 11, 3, 4] ``` ## *移除元素* * #### `clear() → void` ``` var list=[1,2,'a']; list.clear(); print(list); // [] ``` * #### `remove(Object? value) → bool` ``` final parts = <String>['head', 'shoulders', 'knees', 'toes']; var res = parts.remove('head'); // true print(parts); // [shoulders, knees, toes] res=parts.remove('head'); // false ``` * #### `removeAt(int index) → E` ``` final parts = <String>['head', 'shoulder', 'knees', 'toes']; final retVal = parts.removeAt(2); // retVal = knees print(parts); // [head, shoulder, toes] ``` * #### `removeLast() → E` ``` final parts = <String>['head', 'shoulder', 'knees', 'toes']; final retVal = parts.removeLast(); // retVal = toes print(parts); // [head, shoulder, knees] ``` * #### `removeRange(int start, int end) → void` 0 ≤ start ≤ end ≤ this.length ``` final numbers = <int>[1, 2, 3, 4, 5]; numbers.removeRange(1, 4); print(numbers); // [1, 5] ``` * #### `removeWhere(bool test(E element)) → void` 移除符合條件的元素 ``` final numbers = <String>['one', 'two', 'three', 'four']; numbers.removeWhere((item) => item.length == 3); print(numbers); // [three, four] ``` * #### `retainWhere(bool test(E element)) → void` 移除不符合條件的元素 ``` final numbers = <String>['one', 'two', 'three', 'four']; numbers.retainWhere((item) => item.length == 3); print(numbers); // [one, two] ``` ## *替代元素* * #### `fillRange(int start, int end, [E? fillValue]) → void` 用 *值* 填滿某範圍, **可以用在**fixed-length list 0 ≤ start ≤ end ≤ this.length ``` final words = List.filled(5, 'old'); print(words); // [old, old, old, old, old] words.fillRange(1, 3, 'new'); print(words); // [old, new, new, old, old] ``` * #### `replaceRange(int start, int end, Iterable<E> it) → void` **不能用在** fixed-length list 先把 start<=index<end的部分移除, 然後從start處開始填入it的所有元素, 操作完成, list的長度也許會改變 ``` final numbers = <int>[1, 2, 3, 4, 5]; final replacements = [6, 7,8,9,10,11]; numbers.replaceRange(1, 4, replacements); print(numbers); // [1, 6, 7, 8, 9, 10, 11, 5] ``` * #### `setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) → void` **可以用在**fixed-length list list2的前2項跳掉( 只剩[7, 8, 9] ), 填入list1的 1<=index<3, 操作過後list1的長度必須不會變 list2.length-skipCount >= end-start 否則拋出異常 ``` final list1 = List.filled(5, 0); print(list1); // [0, 0, 0, 0, 0] fixed-length list final list2 = <int>[5, 6, 7, 8, 9]; const skipCount = 2; list1.setRange(1, 3, list2, skipCount); print(list1); // [0, 7, 8, 0, 0] ``` * #### `setAll(int index, Iterable<E> iterable) → void` **可以用在** fixed-length list 從index處開始用iterable覆蓋舊元素 iterable.length <= this.length-index 否則拋出異常 ``` final target = List<String>.filled(5, 'old'); target.setAll(1, ['new1', 'new2']); // 等效 target.setRange(1,3,['new1', 'new2'],0); print(target); // [old, new1, new2, old, old] ``` ## *依條件測試所有元素(=> bool)* [Iterable Method](https://hackmd.io/@asdf121472/HkXHn-cgR) ## *排序與打亂* * #### 排序 `sort([int compare(E a, E b)?]) → void` 依據compare()對list做排序 ``` final numbers = <int>[13, 2, -11, 0]; numbers.sort(); // [-11, 0, 2, 13] final strings=<String>['one','two','three','four']; strings.sort(); // [four, one, three, two] strings.sort((a,b)=>a.compareTo(b)); // [four, one, three, two] ``` ``` final numbers = <String>['two', 'three', 'four']; // Sort from shortest to longest. numbers.sort((a, b) => a.length.compareTo(b.length)); print(numbers); // [two, four, three] ``` * #### 打亂 `shuffle([Random? random]) → void` ``` final numbers = <int>[1, 2, 3, 4, 5]; numbers.shuffle(); print(numbers); // [1, 3, 4, 5, 2] OR some other random result. ``` ## *提供視圖* * #### `asMap() → Map<int, E>` List轉成不可修改的Map, keys=index, values=elements ``` var words = <String>['fee', 'fi', 'fo', 'fum']; var map = words.asMap(); // {0: fee, 1: fi, 2: fo, 3: fum} map.keys.toList(); // [0, 1, 2, 3] ``` ## *類型轉換* * #### costructor `List.from(Iterable elements, {bool growable = true})` * #### inherited `static List<T> castFrom<S, T>(List<S> source) => CastList<S, T>(source);` * #### override `cast<R>() → List<R>` ``` var l1 = <int>[1, 2, 3]; // List<int> var listFrom=List<num>.from(l1); // List<num> var iterableCastFrom = List.castFrom<int, num>(l1); // List<num> var overrideCast=l1.cast<num>(); // List<num> ``` # 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 ``` * #### `copyRange<T>(List<T> target, int at, List<T> source, [int? start, int? end]) → void` 把source的 start<=index<end 部分, 填充到target, 從index=at處開始填充, target的長度不會變 end-start<=target.length-at 否則throws error This is a utility function that can be used to implement methods like setRange ``` List target=[1,2,3,4]; List source=[5,6,7,8]; List.copyRange(target, 1, source,1,3); print(target); // [1, 6, 7, 4] // List.copyRange(target, 2, source); // Not big enough to hold 4 elements at position 2: Instance(length:4) of '_GrowableList' ``` * #### `writeIterable<T>(List<T> target, int at, Iterable<T> source) → void` 從index=at處開始, 用source覆蓋target的元素 source.length <= target.length-at 否則throws error This is a utility function that can be used to implement methods like setAll ``` List target=[7,8,9,10,11]; Iterable source=Iterable.generate(3,(index)=>index*index); print(source); // (0, 1, 4) List.writeIterable(target, 1, source); print(target); // [7, 0, 1, 4, 11] // List.writeIterable(target, 3, source); // Index out of range: index should be less than 5: 5 ``` # Operators * #### `operator ==(Object other) → bool` Iterable物件 只會等於自身 ``` List i1=[1,2,3]; List i2=[1,2,3]; List i3=i1; print(i1==i2); // false print(identical(i1, i2)); // false print(i1==i3); // true print(identical(i1, i3)); // true ``` * #### `operator +(List<E> other) → List<E>` ``` List apend=[1,2]+[3,4]; print(apend); // [1, 2, 3, 4] ``` * #### `operator [](int index) → E` ``` final i=[1,2,3]; assert(i[1]==i.elementAt(1)); ``` * #### `operator []=(int index, E value) → void`