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