【Dart】Mapのソート


1. ソートするMap

Map<String, int> scoreMap = {
  'Ichiro' : 80,
  'Kawasaki' : 50,
  'Ariana' : 60,
};

2.1. keyでソート

scoreMap = SplayTreeMap.from(scoreMap, (a, b) => a.compareTo(b));
// 出力結果: {Ariana: 60, Ichiro: 80, Kawasaki: 50}

2.2. 値でソート

NullSafety対応のために2箇所ほど「!」を使用しています。もし必要がない場合は「!」を削除してください。

SplayTreeMap.from(scoreMap, (a, b) => scoreMap[a]!.compareTo(scoreMap[b]!));
// 出力結果: {Kawasaki: 50, Ariana: 60, Ichiro: 80}

SplayTreeMapは相互に関連して並べ替えることができるオブジェクトのマップです。
'dart:collection'をインポートすることでSplayTreeMapを使用できます。

https://api.dart.dev/stable/2.16.1/dart-collection/SplayTreeMap-class.html

3.1. ソートに失敗するケース

Ariana と Kawasakiの値が同じ値の場合、要素から Kawasaki が消えました。
このような場合の対処方法を次の題目で紹介したいと思います。

Map<String, int> scoreMap = {
  'Ichiro' : 80,
  'Kawasaki' : 50,
  'Ariana' : 50,
};

SplayTreeMap.from(scoreMap, (a, b) => scoreMap[a]!.compareTo(scoreMap[b]!));
// 出力結果: {Ariana: 50, Ichiro: 80}

3.2. compareToメソッドを理解しよう

compareToメソッドの動きを確かめてみました。

final List<int> scoreList = [80, 50, 80, 60];

scoreList.sort((a, b) {
  print('$a$b');
  print(a.compareTo(b));
  print('-------------');
  return a.compareTo(b);
});

// 出力結果
// 80と50
// 1
// -------------
// 80と80
// 0
// -------------
// 80と60
// 1
// -------------
// 80と60
// 1
// -------------
// 50と60
// -1
// -------------

compareToメソッドの戻り値は以下の通りです。

  • aの値がbの値よりも大きい場合は「1」
  • aの値とbの値が同じ場合は「0」
  • aの値がbの値よりも小さい場合は「-1」

3.3. 解決策

compareToメソッドの戻り値が0にならないようにすれば良いです。

scoreMap = SplayTreeMap.of(scoreMap, (a, b) {
  int compare = scoreMap[a]!.compareTo(scoreMap[b]!);
  // compareが0(aとbの値が同じ場合)なら1(aがbよりも大きい場合)に置き換える。
  return compare == 0 ? 1 : compare;
});
// 出力結果: {Ariana: 50, Saw: 50, Ichiro: 80}