Dart/Flutter – How to find an item in a list

In this post, we will learn how to find an item in a list in Dart/Flutter through an interesting example.

Suppose we have a class Person with name and age. We need to find in a provided list the person by his name. Here is the Person class:

class Person {
  final String name;
  final int age;

  const Person(this.name, this.age);

  @override
  String toString() {
    return 'Student: {name: ${name}, age: ${age}}';
  }
}


Dart provides many useful methods to filter a list, I will use some of them in below examples, you may find other solutions too.

Using Loop:

/// Find a person in the list using loop.
void findPersonUsingLoop(List<Person> people,
    String personName) {
  for (var i = 0; i < people.length; i++) {
    if (people[i].name == personName) {
      print('Using loop: ${people[i]}');

      // Found the person, stop the loop
      return;
    }
  }
}


Using firstWhere method:

/// Find a person in the list using firstWhere method.
void findPersonUsingFirstWhere(List<Person> people,
    String personName) {
  // Note (from document):
  // 1. Returns the first element that satisfies
  //    the given predicate test. Iterates through
  //    elements and returns the first to satisfy test.
  // 2. If no element satisfies test, the result of
  //    invoking the orElse function is returned.
  //    If orElse is omitted, it defaults to throwing a StateError.
  final person =
      people.firstWhere((element) =>
          element.name == personName,
          orElse: () {
            return null;
  });

  print('Using firstWhere: ${person}');
}


Using indexWhere method:

/// Find a person in the list using indexWhere method.
void findPersonUsingIndexWhere(List<Person> people,
    String personName) {
  // Find the index of person. If not found, index = -1
  final index = people.indexWhere((element) =>
        element.name == personName);
  if (index >= 0) {
    print('Using indexWhere: ${people[index]}');
  }
}


Using singleWhere method:

/// Find a person in the list using [singleWhere] method.
void findPersonUsingSingleWhere(List<Person> people,
    String personName) {
  // Note (from document):
  // 1. If exactly one element satisfies test,
  //    that element is returned.
  // 2. If more than one matching element is found,
  //    throws StateError.
  // 3. If no matching element is found,
  //    returns the result of orElse. If orElse is omitted,
  //    it defaults to throwing a StateError.
  final person = people.singleWhere((element) =>
        element.name == personName, orElse: () {
          return null;
  });

  print('Using singleWhere: ${person}');
}


Using where method:

void findPersonUsingWhere(List<Person> people,
    String personName) {
  // Return list of people matching the condition
  final foundPeople = people.where((element) =>
        element.name == personName);

  if (foundPeople.isNotEmpty) {
    print('Using where: ${foundPeople.first}');
  }
}


Using retainWhere method:

/// Find a person in the list using retainWhere method.
/// We probably don't use [retainWhere] method to find
/// element in real, because this method will modify
/// original list (remove all others elements which
/// do not match the condition). [retainWhere] method keeps
/// all elements match the condition. Therefore, the result
/// could contain more than one element.
void findPersonUsingRetainWhere(List<Person> people,
    String personName) {
    people.retainWhere((element) =>
        element.name == personName);
    if (people.isNotEmpty) {
      print('Using retainWhere: ${people[0]}');
    }
}

Let me put all the code together, and show you the output:

void main() {
  final people = [
    Person('Alice', 20),
    Person('Bob', 22),
    Person('Chris', 30),
    Person('Dan', 24),
    Person('Elly', 27)
  ];

  final personName = 'Chris';

  findPersonUsingLoop(people, personName);
  print('----------');
  findPersonUsingFirstWhere(people, personName);
  print('----------');
  findPersonUsingIndexWhere(people, personName);
  print('----------');
  findPersonUsingSingleWhere(people, personName);
  print('----------');
  findPersonUsingWhere(people, personName);
  print('----------');
  findPersonUsingRetainWhere(people, personName);
}

/// Find a person in the list using loop.
void findPersonUsingLoop(List<Person> people,
    String personName) {
  for (var i = 0; i < people.length; i++) {
    if (people[i].name == personName) {
      print('Using loop: ${people[i]}');

      // Found the person, stop the loop
      return;
    }
  }
}

/// Find a person in the list using firstWhere method.
void findPersonUsingFirstWhere(List<Person> people,
    String personName) {
  // Note (from document):
  // 1. Returns the first element that satisfies
  //    the given predicate test. Iterates through
  //    elements and returns the first to satisfy test.
  // 2. If no element satisfies test, the result of
  //    invoking the orElse function is returned.
  //    If orElse is omitted, it defaults to throwing a StateError.
  final person =
      people.firstWhere((element) =>
          element.name == personName,
          orElse: () {
            return null;
  });

  print('Using firstWhere: ${person}');
}

/// Find a person in the list using indexWhere method.
void findPersonUsingIndexWhere(List<Person> people,
    String personName) {
  // Find the index of person. If not found, index = -1
  final index = people.indexWhere((element) =>
        element.name == personName);
  if (index >= 0) {
    print('Using indexWhere: ${people[index]}');
  }
}

/// Find a person in the list using [singleWhere] method.
void findPersonUsingSingleWhere(List<Person> people,
    String personName) {
  // Note (from document):
  // 1. If exactly one element satisfies test,
  //    that element is returned.
  // 2. If more than one matching element is found,
  //    throws StateError.
  // 3. If no matching element is found,
  //    returns the result of orElse. If orElse is omitted,
  //    it defaults to throwing a StateError.
  final person = people.singleWhere((element) =>
        element.name == personName, orElse: () {
          return null;
  });

  print('Using singleWhere: ${person}');
}

void findPersonUsingWhere(List<Person> people,
    String personName) {
  // Return list of people matching the condition
  final foundPeople = people.where((element) =>
        element.name == personName);

  if (foundPeople.isNotEmpty) {
    print('Using where: ${foundPeople.first}');
  }
}

/// Find a person in the list using retainWhere method.
/// We probably don't use [retainWhere] method to find
/// element in real, because this method will modify
/// original list (remove all others elements which
/// do not match the condition). [retainWhere] method keeps
/// all elements match the condition. Therefore, the result
/// could contain more than one element.
void findPersonUsingRetainWhere(List<Person> people,
    String personName) {
    people.retainWhere((element) =>
        element.name == personName);
    if (people.isNotEmpty) {
      print('Using retainWhere: ${people[0]}');
    }
}

class Person {
  final String name;
  final int age;

  const Person(this.name, this.age);

  @override
  String toString() {
    return 'Student: {name: ${name}, age: ${age}}';
  }
}


Output:

Using loop: Student: {name: Chris, age: 30}
----------
Using firstWhere: Student: {name: Chris, age: 30}
----------
Using indexWhere: Student: {name: Chris, age: 30}
----------
Using singleWhere: Student: {name: Chris, age: 30}
----------
Using where: Student: {name: Chris, age: 30}
----------
Using retainWhere: Student: {name: Chris, age: 30}
Tagged : / / /
Subscribe
Notify of
guest

7 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Bear
Bear
1 year ago

Best

Huzaifa
Huzaifa
1 year ago

Very nice way of explaining using different methods

Gift
Gift
1 year ago

Thank you

Mujahid
Mujahid
2 years ago

Thank you, this helped me.
I wish there is a share button!

7
0
Would love your thoughts, please comment.x
()
x