top of page

[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>を使っています(あくまで個人的な手法ですが)。

最新記事

すべて表示

【Flutter/Dart】TextFieldで文字列をフォーマットする

やりたいこと TextFieldで入力フォームを作りたい。 例えば入力内容が金額の場合、3桁区切りで頭に¥を付けた表記にしたい。 ただしユーザにこれらを入力させるのではなく、ユーザはあくまで数字を入力するだけで、アプリ側で自動でフォーマットしたい。 方法 TextInputFormatterを継承し、所望のフォーマット処理を追加することで実現可能。 例えばこの記事などを参照。 以下は個人的に躓いた

【Flutter/Dart】iosシミュレータ起動後にデバイスに保存した画像が見つからない

現象 やってること iosシミュレータで画像をデバイスのローカルに保存 保存したパスをデータベースに保存 アプリ立ち上げ時にデータベースから画像パスを取得し、そのパスの画像を画面上に表示 起きている現象 iosシミュレータを再起動した場合、上記3で「ファイルパスが見つからない」というエラーが出る 原因 保存時のディレクトリを getApplicationDocumentsDirectory() に

【Flutter/dart】late変数が初期化されたかのチェック

やりたいこと 初期値さえ決まればあとは不変な変数がある ただし、コンストラクタ起動時にはまだ決定できない このような変数について late finalで変数を定義 (何らかのタイミングで)初期化されたかどうかをチェックし、されていなければ値を入れる(チェックしないとfinalに値を代入したエラーになるので) この場合、「初期化されたかどうか」はどのようにチェックしたらいいのか分からなかった nul

コメント


あなたの買い物をサポートする
アプリ Shop Plan

iphone6.5p2.png

​いつ何を買うかの計画を立てられるアプリです。

google-play-badge.png
Download_on_the_App_Store_Badge_JP_RGB_blk_100317.png

靴を大切にしよう!靴管理アプリ SHOES_KEEP

納品:iPhone6.5①.png

靴の履いた回数、お手入れ回数を管理するアプリです。

google-play-badge.png
Download_on_the_App_Store_Badge_JP_RGB_blk_100317.png

「後で読む」を忘れないアプリ ArticleReminder

気になった​Webサイトを登録し、指定時刻にリマインダを送れるアプリです

google-play-badge.png
Download_on_the_App_Store_Badge_JP_RGB_blk_100317.png
bottom of page