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

6 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Huzaifa
Huzaifa
25 days ago

Very nice way of explaining using different methods

Gift
Gift
27 days ago

Thank you

Mujahid
Mujahid
6 months ago

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

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