0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Dart】Mapの中に該当する要素が含まれているかどうかの検索

Posted at

こんにちは、がきけです!
DartのMapについて、自作のクラスを用いた要素の検索でつまずいたので、
備忘録としてまとめます。

Mapに自作クラスの形式で要素が入っている場合の検索方法

やりたかったこと

今回つまずいたのは、以下に記載したコードのように、
Mapの要素の形式がStringなどの既存の型ではなく、自作したクラスで、
クラスの中にuserNameやcreatedDateなど複数の要素が入っている場合に、
Mapのvalueに該当するユーザーが登録されているかどうかを確認する方法です。

void main() {
  // 登録しているユーザーのデータ(自作のクラス'User'の形式で要素を登録)
  Map<String,User> users = {
    '1': User(userName: 'user1', createdDate: DateTime(2022, 11, 1)),
    '2': User(userName: 'user2', createdDate: DateTime(2022, 11, 2)),
  };
  
  bool checkUser(String checkUserName, DateTime checkDate){
    // ここに該当するユーザーが登録されているかどうかを判定するコードを書く
  }
  
  print(checkUser('user1',DateTime(2022,11,1))); // trueで返してほしい
  print(checkUser('user3',DateTime(2022,11,3))); // falseで返してほしい
}

class User{
  final String userName;
  final DateTime createdDate;
  
  User({
    required this.userName,
    required this.createdDate,
  });
}

containsValueは失敗

「あるかどうか」がほしかったので、bool型で返してほしいなーと思い、
最初に試してみたのがcontainsValueメソッド。
Mapのvalueの中に、該当する要素があるかどうかを確認することができるメソッドです。
こんな感じでcheckUserの中身を書きました。

void main() {
  // 登録しているユーザーのデータ
  Map<String,User> users = {
    '1': User(userName: 'user1', createdDate: DateTime(2022, 11, 1)),
    '2': User(userName: 'user2', createdDate: DateTime(2022, 11, 2)),
  };
  
  bool checkUser(String checkUserName, DateTime checkDate){
    bool isUser;
    
    // ここ
    users.containsValue(User(userName: checkUserName, createdDate: checkDate)) ? isUser = true : isUser = false;

    return isUser;
  }
  
  print(checkUser('user1',DateTime(2022,11,1))); // trueで返してほしい
  print(checkUser('user3',DateTime(2022,11,3))); // falseで返してほしい
}

が、しかしこれが失敗。
checkUser('user1',DateTime(2022,11,1))をtrueで返してほしかったのですが、falseで返ってきてしまいました。
どうやらcontainsValueはStringやDateTime単体であればうまくいくのですが、
今回のUserのように、複数の要素があるvalueについては検索ができないようなのです。

void main() {
  // これだとうまくいく
  Map<String,DateTime> users = {
    'user1': DateTime(2022, 11, 1),
    'user2': DateTime(2022, 11, 2),
  };
  
  bool checkUser(String checkUserName, DateTime checkDate){
    
    bool isUser;

    // DateTime型の要素だけで検索
    users.containsValue(checkDate) ? isUser = true : isUser = false;
    
    return isUser;
  }
  
  print(checkUser('user1',DateTime(2022,11,1))); // trueで返ってきました
  print(checkUser('user3',DateTime(2022,11,3))); // falseで返ってきました
}

where.isNotEmptyで成功

さてどうしようということで、bool型で返ってこなくても、
「該当するものがあればそれを返してー」と言って1つ以上返ってきたらtrue、
返ってこなかったらfalseにするようにすればいいかなーと思い、whereで要素を検索することにしました。
map.entries.where((element) => 条件式)で、条件式に合う要素をすべて取得することができます。

すると、map.entries.where((element) => 条件式)に.isNotEmptyをつけることで、
条件式に合う要素があるかどうかをbool型で取得することができることを発見。
実行してみたところ、正常に動作し、目的を達成することができました。

void main() {
  Map<String,User> users = {
    '1': User(userName: 'user1', createdDate: DateTime(2022, 11, 1)),
    '2': User(userName: 'user2', createdDate: DateTime(2022, 11, 2)),
  };
  
  bool checkUser(String checkUserName, DateTime checkDate){
    
    bool isUser;
    
    // Mapに登録されているuserNameと引数で渡されたcheckUserNameが一致して、
    // かつMapに登録されているcreatedDateと引数で渡されたcheckDateが一致した場合のみtrueを返すようにしました
    users.entries.where((element) => element.value.userName == checkUserName && element.value.createdDate == checkDate).isNotEmpty ? isUser = true : isUser = false;

    return isUser;
  }
  
  print(checkUser('user1',DateTime(2022,11,1))); // trueで返ってきました
  print(checkUser('user3',DateTime(2022,11,3))); // falseで返ってきました
}

今後の課題

「containsValueでは自作クラスの形式で登録された要素を検索できない」というのは、
ちゃんと公式ドキュメントに書いてあったわけではなくて、
自分で動かしてみて、そうなのかな? と思ったことです。
なので、より詳しいことをご存知の方がいらっしゃいましたら、コメントでご教示いただければ幸いです。

また、「もっといい書き方あるよー」や「こんなんどう?」などありましたら、
同じくコメントいただければ嬉しいです。よろしくお願いします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?