Working with list in Dart.
Published: 2020-02-19 18:39:05

A very commonly used collection in programming is an array. Dart represents arrays in the form of List objects. A List is simply an ordered group of objects. The dart:core library provides the List class that enables creation and manipulation of lists.

Lists are Iterables
An iterable provides a means to traverse items some sort of a list in a sequential fashion.  Dart takes an approach similar to most other programming languages.  Basically you have what is known as an iterator which keeps track of the current item in a list and allows you to move forward through the list using a 'next' method.  More on Dart's Iterator can be found on the dart website  however in practice you will find you are almost always working with some sort of abstraction of the iterator, not the iterator itself.  There are multiple classes in the dart library that you can iterate and some you will work with more than others.  List is a workhorse and you'll find it being your go-to more often than not.  But it's certainly worth knowing about others such as Set, Map, and Queue.

Here is what we will cover in this article:

Creating Lists
Looping
Filtering
Mapping
Sorting

Creating Lists
There are many different ways to create a list.  At times you'll know the length of your list, and at times you won't.  Both approaches are easily accommodated by dart.  There are even means to dynamically generate a list.  Here are some common examples of creating a list of strings.  I chose strings but as you can imagine, any type here would work:

void main() {
  
  //Fix lengthed list
  var namesFixed = new List<String>(3);
  namesFixed[0] = "Joe";
  namesFixed[1] = "Frankie";
  namesFixed[2] = "Tom";
  //namesFixed[3] = "Kaboom!"; //this would be an error
  log(namesFixed)  ;
  
  //Growable list
  var namesGrowable = new List<String>();
  namesGrowable.add("Joe");
  namesGrowable.add("Frankie");
  namesGrowable.add("Tom");
  namesGrowable.add("Larry");
  log(namesGrowable) ;
  
  //List initialized upfront
  List<String> names = ["Joe", "Frankie", "Tom"];
  log(names);
  names.add("Dave"); //Can add just fine, since this one is growable too!
  log(names);
  
  //Using filled to set placeholder values on a fixed length list of 3
  var namesFilled = new List<String>.filled(3, "placeholder");
  log(namesFilled); //prints placeholder 3 times...
  namesFilled[0] = "Joe"; //Update first entry
  namesFilled[1] = "Frankie"; //Update second entry
  log(namesFilled);
  
  //Using generate (useful to create a long list of something like test data or to call a generator function)
  List<String> namesGenerated = new List<String>.generate(3, (i) => "Name ${i}");
  log(namesGenerated);
}

void log(List<String> lst) {
  lst.forEach((n) => print(n));
  print('=========');
}

Looping
Looping through a list is very common.  For example:

void main() {
  List<String> names = ["Joe", "Frankie", "Tom"];
  for (var n in names) {
    print('Hello ${n}');
  }
}

What the above code does is establish a list of strings that contain names.  Then we create a for loop and print the name out to the console.  Here is another way to iterate that list of names:

void main() {
  List<String> names = ["Joe", "Frankie", "Tom"];
  names.forEach((n) => 
    print('Hello Mr. ${n}'));
}

I like the forEach approach with a fat arrow (=>) function but the examples essentially do the same thing.

Filtering
Filtering comes into play from the where method:

void main() {
  List<double> prices = [0.25, 1.00, 3.33, 0.75, 4.25, 5.99];  
  var overOneDollar = prices.where((p) => p > 1.00);
  log(overOneDollar); //prints 3.33, 4.25, 5.99
}
  
void log(var lst) {
  lst.forEach((n) => print(n));
}

Essentially what is happening in the above code is each price is examined in the fat arrow function and if it is greater than one dollar it passes the condition and is added to the overOneDollar result.

Mapping
Mapping allows you to take a List and transform it into something else a'la the map method.  For example:

class Person 
{
  String firstName;
  String lastName;
  
  Person(this.firstName, this.lastName);
}

void main() {
	List<Person> people = new List<Person>();
  people.add(new Person("Joe", "Smithers"));
  people.add(new Person("Patrick", "Thomas"));
  var mappedNames = people.map((n) => 'Mr. ${n.firstName} ${n.lastName}');
  log(mappedNames);
}
  
void log(var lst) {
  lst.forEach((n) => print(n));
}


Sorting
The sort method allows you to sort.  Default types like numbers and strings don't need much to get started:

void main() {
  List<double> prices = [0.25, 1.00, 3.33, 0.75, 4.25, 5.99];  
  prices.sort();
  log(prices); //prints 0.25, 0.75, 1, 3.33, 4.25, 5.99
  
  List<String> alphabet = ["b", "c", "a"];
  alphabet.sort();
  log(alphabet); //prints a,b,c
}
  
void log(var lst) {
  lst.forEach((n) => print(n));
}

Sorting numbers and strings is straight-forward.  But what if you had a list of objects to sort?  Here is an example that takes a list of Employees and ranks their Sales with the Employee with the most Sales being displayed on top and so forth:

class Sale {
  int employeeId;
  double price;
  Sale(this.employeeId, this.price);
}

class Employee {
  int id;
  List<Sale> sales;
  Employee (this.id, this.sales);  
}

void main() {
  //Create a list of employees and their respective sales
  List<Employee> employees = new List<Employee>();
  employees.add(new Employee(1, [new Sale(1, 100.50), new Sale(1, 300.25)]));
  employees.add(new Employee(2, [new Sale(2, 300.00), new Sale(2, 50.25), new Sale(2, 150.00)]));
  employees.add(new Employee(3, [new Sale(2, 400.00), new Sale(2, 30.75), new Sale(3, 50.00)]));
  //Sort so that the employee with the most sales is on top and so on...
  employees.sort((a, b) => (b.sales.fold(0, (prev, element) => prev + element.price)).compareTo(a.sales.fold(0, (prev, element) => prev + element.price)));
  log(employees); //prints Employee #2, followed by Employee #3, then ending with Employee #1
}
  
void log(var lst) {
  lst.forEach((l) => print("Employee #${l.id} has ${l.sales.length} sales totaling ${l.sales.fold(0, (prev, element) => prev + element.price)} dollars!"));
}

This should give you a good start on working with lists.  But you should explore the other types of collections Dart has as well.