この章では Flutter 開発でもよく使うことになる List と Map を操作するメソッドについて学んでいきます。
List/Map 操作のメソッドは数が多いので、よく使われる代表的なメソッドをピックアップしてご紹介していきます。それでも数が非常に多いので、サラッと読み流し、実際に使う時にまた戻ってくるという感じで読んでみていただければと思います。
List 操作
List 操作については追加、削除、判定、検索、並べ替え、展開、変換、合体、コピーといった操作のメソッドを紹介していきます。
より詳しく学びたい方はこちらを参考にしてみてください
追加する
add
単一の要素を配列の最後尾に追加します
void main(){
// Create a list
List<String> colors = ["red", "green"];
// Add a new item to the list
colors.add("blue");
// The list now contains three elements
print(colors); // ["red", "green", "blue"]
}
addAll
同じ型を格納する配列の中身を全て配列の最後尾に追加します
void main(){
// Create a list
List<String> colors = ["red", "green"];
// Create another list
List<String> moreColors = ["yellow", "orange"];
// Add the items from the second list to the first list
colors.addAll(moreColors);
// The list now contains four elements
print(colors); // ["red", "green", "yellow", "orange"]
}
削除する
remove
指定した要素を配列から削除します
void main(){
List<String> myList = ['a', 'b', 'c'];
myList.remove('b');
print(myList); // output: [a, c]
}
removeWhere
removeWhere
に渡された条件式に合致する要素を配列を削除します
void main(){
List<int> myList = [1,300,345,501,1000];
// ex. 500よりも小さい要素を削除
myList.removeWhere((int el)=> el < 500);
print(myList); // output: [501, 1000]
}
展開して判定する
contains
配列内に指定の値を持つ要素が存在するかを判定します
void main() {
List<int> list = [1, 2, 3, 4, 5];
print(list.contains(3)); // true
print(list.contains(6)); // false
}
any
any()
に渡された条件に合致する要素が存在するかを判定します
void main() {
List<int> list = [1, 2, 3, 4, 5];
print(list.any((element) => element > 4)); // true
print(list.any((element) => element < 0)); // false
}
every
every()
に渡された条件に全ての要素が合致するかを判定します
void main() {
List<int> list = [1, 2, 3, 4, 5];
print(list.every((element) => element < 6)); // true
print(list.every((element) => element > 1)); // false
}
検索する
where
where()
に渡された条件に合致する要素を抽出し、後述のtoList()
と併せて使うことで新しい配列を返します。条件に合致する要素がない場合は空の配列が生成されます。
void main(){
final List<int> list = [1, 2, 3, 4, 5];
final List<int> filteredList = list.where((i) => i >= 3).toList();
print(filteredList); // [3, 4, 5]
}
firstWhere
firstWhere()
に渡された条件に合致する最初の要素を返します。orElse
には条件に合致する要素がない場合の処理を記述します。
void main(){
final List<int> list = [1, 2, 3, 4, 5];
int firstFilteredItem = list.firstWhere((i) => i >= 3, orElse: () => -1);
print(firstFilteredItem); // 3
int secondFilteredItem = list.firstWhere((i) => i >100, orElse:()=> -1);
print(secondFilteredItem); // -1
}
sublist
指定した範囲の要素を返します。第一引数だけ指定した場合はその要素以降の要素を全て、第二引数まで指定した場合は第一引数の要素から第二引数の要素の1つ前までを全て返します。
void main(){
List<String> list = ['monkey', 'elephant', 'tiger','dragon','whale'];
List<String> subList = list.sublist(1);
print(subList);
// output: [elephant, tiger, dragon, whale]
List<String> subList2 = list.sublist(1,3);
print(subList2);
// output: [elephant, tiger]
}
インデックスを検索する
indexOf
指定した要素のインデックス番号を返します。もし要素が存在しない場合は-1
が返ってきます。
void main(){
var list = [1, 2, 3];
var indexOf2 = list.indexOf(2);
print(indexOf2); // 1
final int indexOf4 = list.indexOf(4);
print(indexOf4); // -1
}
indexWhere
indexWhere()
に渡された条件に合致する最初の要素のインデックスを返します。条件に合致する要素が複数あっても返ってくるのは最初の要素のインデックスだけです。
また条件に合致する要素がなければ-1
が返ってきます。
void main(){
var list = [1, 2, 3];
var indexWhere2 = list.indexWhere((element) => element == 3);
print(indexWhere2); // 2
final int indexOver1 = list.indexWhere((element)=>element >1);
print(indexOver1); // 1
final int indexWhere4 = list.indexWhere((element)=>element == 4);
print(indexWhere4); // -1
}
並べ替える
sort
sort()
に渡した条件で配列を並び替えます。コールバックで(最初の要素、次の要素)
の値を受け取るので、それらの比較条件を記述し、インデックスを後ろにズラす時は1
を、前にズラす時は-1
、動かさない時は0
を返す事で配列を並び替えます。
同様の処理はcompareTo
関数をを使う事でも実現できるのでそちらを使った方がスマートに記述できます。
また条件を渡さずに実行すると昇順に要素を並び替えます。
void main() {
List numbers = [3, 2, 4, 7, 5, 6, 1];
// ex.大きい順に並べる(降順)
numbers.sort((a, b){
if (a < b) return 1;
if (a > b) return -1;
return 0;
});
print(numbers); // [7, 6, 5, 4, 3, 2, 1]
// compareToを使う
numbers.sort((a,b)=>b.compareTo(a));
print(numbers);// [7, 6, 5, 4, 3, 2, 1]
// ex.小さい順に並べる(昇順)
numbers.sort();
print(numbers); // [1, 2, 3, 4, 5, 6, 7]
}
shuffle
配列をランダムに並べ替えます
void main() {
List numbers = [3, 2, 4, 7, 5, 6, 1];
numbers.shuffle();
print(numbers); // [4, 2, 7, 6, 1, 5, 3](ランダムの為、出力結果は毎回異なります)
}
展開してコレクションにする
map
+toList
配列をイテレータ型という順々に値を返す型に変換します。単体で用いる事は少なく、後述するtoList
と一緒に用いることが多いです。
map
を使うことで配列内の要素を1つ1つ取り出し、何かしらの処理を施すことができます。
void main(){
// list.mapのサンプルコード
List<int> nums = [1,2,3,4,5];
List<int> squares = nums.map((n) => n * n).toList();
print(squares); // [1, 4, 9, 16, 25]
}
expand
+toList
expand
はmap
に似ていますが、配列の値を再起的に展開し、何かしらの処理を施し、再度コレクションに変換して返します。
特に有効なのが二次元配列などネストした配列構造を1つの配列にしたい様な場合です。
javascript
が分かる方はArray.flat()
をイメージして頂ければ良いと思います。
void main() {
var a = [
[1, 2, 3],
['a', 'b', 'c'],
[true, false, true]
];
// ネストした配列の要素を全て展開して、単一の配列に格納
var flat = a.expand((i) => i).toList();
print(flat);
// [1, 2, 3, a, b, c, true, false, true]
// mapでは再起処理されず、配列のまま配列に格納してしまう
var flat2 = a.map((i)=>i).toList();
print(flat2);
// [[1, 2, 3], [a, b, c], [true, false, true]]
}
変換する
asMap
配列の各要素にキーとしてインデックスをふり、Map
に変換します
void main() {
List<String> list = ['a', 'b', 'c'];
Map<int, String> myMap = list.asMap();
print(myMap); // {0: a, 1: b, 2: c}
}
toList
単体で使う場合は配列を配列に変換することになる為、あまり用いず、前述のwhere
、map
やexpand
と併用して使う事が多いです。
Set
を配列に変換することもできます。(厳密には Set が持つtoList
メソッドですが)
void main(){
Set<String> mySet = {'a','b','c'};
print(mySet); // {a, b, c}
List<String> myList = mySet.toList();
print(myList); // [a, b, c]
}
toSet
配列を重複不可なSet
に変換します
void main() {
List<int> list = [1, 4, 5, 24, 4, 24];
final Set<int> mySet = list.toSet();
print(mySet); // {1, 4, 5, 24}
}
合体させる
join
String
型の配列の値を引数に渡した文字列で繋いだ1つの文字列にして返します。String
型の配列に対してのみ使用できます。
void main() {
List<String> list = ['Hello', 'World', '!'];
String result = list.join(',');
print(result); // Hello,World,!
}
reduce
配列の要素を1つの値に集約します。(現在の集約値,要素のvalue){処理}
のコールバック関数を渡します。
void main(){
List<String> list = ['Hello', 'World', '!'];
String result = list.reduce((substr, element) {
return substr + element;
});
print(result); // HelloWorld!
}
fold
reduce
同様に配列の要素を1つの値に集約します。第一引数に初期値、第二引数では(現在の集約値,要素のvalue){処理}
のコールバック関数を渡します。
reduce
と非常によく似ていますが、2つの特徴があります
- 初期値を設定する事ができる
- 元の要素の型とは別の型に変換する事ができる
特に2は場合によっては非常に便利です。
main(){
List<String> list1 = ['Hello', 'World', '!'];
String result = list1.fold('', (substr, element) => substr + element);
print(result); // HelloWorld!
// ex.文字列の配列から合計の文字数を返します
List<String> list2 = ['apple', 'orange', 'banana'];
final int totalLength = list2.fold(0, (int value, String element) => value + element.length);
print(totalLength); //17
}
コピーする
from
既存の配列を中身そのままでコピーします
void main(){
List<String> list = ['A', 'B', 'C'];
print(list); // [A, B, C]
List<String> newList = List.from(list);
print(newList); // [A, B, C]
}
Map 操作
Map 操作については追加、削除、更新、検索、展開のメソッドを紹介していきます。
こちらもより詳しく学びたい方は以下を参照してみてください。
追加する
addAll
指定した連想配列を最後尾に追加します。既に存在しているキーを代入した場合、その値が上書きされます。
void main() {
Map map1 = {
'key1': 'value1',
'key2': 'value2',
};
Map map2 = {
'key2': 'new value2',
'key3': 'value3',
};
map1.addAll(map2);
print(map1);
// {key1: value1, key2: new value2, key3: value3}
}
addEntries
addAll
が連想配列に連想配列を追加するのに対して、addEntries
は連想配列の要素を追加します。
連想配列の各要素はMapEntry
というオブジェクトになっており、このMapEntry
の配列を渡すことで連想配列に要素を追加します。
Map.entries
で Map の要素を取得する事も可能です。
またaddAll
と同様に既に存在しているキーを代入した場合、その値が上書きされます。
void main() {
final Map<String, String> map1 = {
'key1': 'value1',
'key2': 'value2',
};
final Map<String, String> map2 = {
'key3': 'value3',
'key4': 'value4',
};
map1.addEntries(map2.entries); // Mapの要素を取得
print(map1);
// {key1: value1, key2: value2, key3: value3, key4: value4}
map1.addEntries([
MapEntry('key5', 'value5'),
MapEntry('key6', 'value6'),
]);
print(map1);
// {key1: value1, key2: value2, key3: value3, key4: value4, key5: value5, key6: value6}
}
削除する
remove
指定したキーを持つ要素を連想配列から削除します
void main() {
final Map<String, int> myMap = {'JA': 81, 'GB': 44, 'US': 1, 'CH':44};
myMap.remove('GB');
print(myMap); // {JA: 81, US: 1, CH: 44}
}
removeWhere
指定した条件に合致する要素を全て連想配列から削除します。コールバック関数としてkey
,value
どちらも受け取る為、どちらの値も条件判定に使う事ができます。
void main() {
final Map<String, int> myMap = {'JA': 81, 'GB': 44, 'US': 1, 'AU': 1};
myMap.removeWhere((key, value) => value == 1);
print(myMap); // {JA: 81, GB: 44}
}
更新する
update
指定したキーのバリューに任意の処理を施して更新する事ができます。
指定したキーが存在しない場合、ifAbsent
で返す値をバリューとして、要素を追加します。
void main() {
Map<String, int> scores = {
'Bob': 35,
'Alice': 42
};
scores.update('Bob', (value) => value + 5);
print(scores); // {Bob: 40, Alice: 42}
scores.update('John', (value) => value + 5, ifAbsent:()=> 0);
print(scores); // {Bob: 40, Alice: 42, John: 0}
}
updateAll
連想配列内の全ての要素に対して、任意の処理を施し更新します。
void main() {
Map<String, int> scores = {
'Bob': 35,
'Alice': 42
};
scores.updateAll((key, value) => value + 10);
print(scores); // {Bob: 45, Alice: 52}
}
検索する
containsKey
指定したキーの要素が存在するかを判定します
void main() {
Map<String, int> students = {
'John': 12,
'Bob': 13
};
print(students.containsKey('John')); // true
print(students.containsKey('Jake')); // false
}
containsValue
指定したバリューの要素が存在するかを判定します
void main() {
Map<String, int> students = {
'John': 12,
'Bob': 13
};
print(students.containsValue(13)); // true
print(students.containsValue(15)); // false
}
展開する
map
連想配列の各要素のキーとバリューに対して指定の処理を施した連想配列を返します。処理を施した要素を返す必要がある為、変更を加えたMapEntry
を返す必要があります。
void main(){
Map<String, int> numbers = {
'one': 1,
'two': 2,
'three': 3,
};
Map<String, int> numbersPlusOne = numbers.map((key, value) => MapEntry(key, value + 1));
print(numbersPlusOne); // {one: 2, two: 3, three: 4}
}
forEach
連想配列の各要素を取得し指定の処理を実行する事ができます。map
のように値を返すわけではないので、キーとバリューを用いたなんらかの処理を行うのみです。for in
と同等の動きになります。
void main(){
Map<String, int> numbers = {
'one': 1,
'two': 2,
'three': 3,
};
numbers.forEach((key, value) {
print('key: $key, value: $value');
});
// key: one, value: 1
// key: two, value: 2
// key: three, value: 3
}
操作を組み合わせる
上記の操作関数は1つのコレクションに対し、複数繋げて実行する事ができます。
expand
やwhere
などコレクションを返す関数はいくつでも繋げることができますが、toList
やfold
など1つの値もしくはオブジェクトを確定する処理は最後尾に一度しか実行する事ができません。
複数繋げることが可能
where
、expand
、map
など
一度だけ実行可能
toList
、toSet
、includes
、every
、asMap
、reduce
など
void main() {
final List<int> myList = [9, 8, 39, 0, 15, 62, 90, 18, 70, 66];
final List<int> updatedList =
myList
.where((element) => 10 < element)
.map(((e) => e * e))
.toList();
print(updatedList); // [1521, 225, 3844, 8100, 324, 4900, 4356]
}
まとめ
非常に多くの操作関数が用意されているので、眩暈がしてしまうかもしれませんが、頭の片隅に置いておいて、いざ操作が必要になった時に、そんな関数があったなと使い方を調べ直す、くらい気持ちで臨みましょう。
次章から、いよいよ Flutter へ 🚀
以上で簡単ではありますがDart
の基礎について学んでいきました。次の章からはいよいよFlutter
の解説に入っていきます!!