[Flutter/dart]Mapの要素の並び替えや抽出
概要
Flutterでのアプリ作成において、僕はユーザデータなどをMapで保持することが多いです(listだとデータを削除したときのindexのずれへの対応が面倒なため)。その場合、データを画面上に表示する際に、順番を規定したり特定の条件のデータだけを取り出したりするには一工夫必要です。(C#のdictionaryはlistと同じように扱えるのにな、、、)
方法
MapをMapEntryのlistに変換すればwhereやsortなどのメソッドが使えます。あとは使う側(基本的にはWidgetのbuildのはず)で引数をList<MapEntry>に取ればよい。
並び替え
以下では複数の並び替え方法に対応できるように比較方法をデリゲートで渡すメソッドにしています。
class UserData{
String name;
int score;
UserData({this.name, this.score});
}
class MyHomePageState extends State<MyHomePage> {
Map<int, UserData> data;
@override
void initState() {
data={
0: UserData(name: "Alice", score: 90),
1: UserData(name: "Bob", score: 87),
2: UserData(name: "Charlie", score: 98),
};
}
@override
Widget build(BuildContext context) {
//scoreの低い順に並び替え
var _entries=_orderData(data, (a, b) => (a.value as
UserData).score.compareTo((b.value as UserData).score));
return Scaffold(
appBar: AppBar(
title: Text('demo'),
),
body: Container(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: _entries.map((e) => ListTile(
title: Text(
"${e.value.name}: ${e.value.score}",
style: TextStyle(
fontSize: 16
),
),
)).toList(),
)
)
);
}
//これ!
List<MapEntry> _orderData(Map<int, dynamic>maps, int
Function(MapEntry<int, dynamic>, MapEntry<int, dynamic>) sorter){
return maps.entries.toList()..sort((a, b)=> sorter(a, b));
}
}

抽出
同じく条件を表すデリゲートを引数にしたメソッドを作ります。
List<MapEntry> _selectData(Map maps, bool Function(MapEntry) predicate){
return maps.entries.toList().where((element) =>
predicate(element)).toList();
}
@override
Widget build(BuildContext context) {
//scoreが90以上のデータを抽出
var _entries=_selectData(data, (e) => e.value.score>90);
return Scaffold(
appBar: AppBar(
title: Text('demo'),
),
body: Container(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: _entries.map((e) => ListTile(
title: Text(
"${e.value.name}: ${e.value.score}",
style: TextStyle(
fontSize: 16
),
),
)).toList(),
)
)
);
}

最後に
個人としては、データ保持は検索や削除のしやすさを考えてMap、widgetに一覧表示する場合は並び替えや条件抽出のしやすさを考えてList<MapEntry>を使っています(あくまで個人的な手法ですが)。
最新記事
すべて表示現象 アプリ内にAdmobを追加して、アプリを起動すると、下記のエラーが発生 java.lang.RuntimeException: Unable to get provider com.google.android.gms.ads.MobileAdsInitProvider 原因 AndroidManifestの書き方が誤っていた。 <meta-data>はactivityと同じ階層にある必要が
概要 Uriを持っていて、Urlに変換したい場合の方法で少し手惑ったので共有します 方法 String url = uri.toString(); これだけです。 最後に ページを開くだけだとUriでもUrlでもいいんですが、WebViewはUrlを要求してくるんですよね。
問題 以前、日本語を含むURLを開くためには、エンコーディングしてやる必要がある、という記事を書きました。 しかし、すでにエンコーディングされているURLを再度エンコーディングしてしまうと、別のURLになってしまいます。 つまり、URLを開く処理の前に、 ・エンコーディングが必要なURLか ・すでにエンコーディングがされているか を判定しないといけないことになります。これは中々煩雑な処理です。 発