Exploring Array Manipulation in Dart & Flutter

Emmanuel Unyime
6 min readMar 8, 2024

When working with Flutter, understanding how to manipulate lists efficiently is crucial for building responsive and performant UIs. Dart provides a rich set of methods for manipulating lists, allowing developers to filter, transform, and extract data with ease.

Let’s see some of these methods if you want to jump to see real flutter implementations of array manipulation in widget trees, skip to the “Using Flutter Widgets with Array Manipulation” section.

1. Filtering Lists

Filtering lists allows you to extract elements based on specific criteria. Dart provides the where method for this purpose.

void main() {
List<String> fruits = ['apple', 'banana', 'grape', 'orange', 'kiwi'];

// Filter fruits starting with 'a'
List<String> aFruits = fruits.where((fruit) => fruit.startsWith('a')).toList();

print(aFruits); // Output: [apple]
}

- Working with Lists of Objects

Manipulating lists of objects, such as Map<String, dynamic>, follows similar principles.

void main() {
List<Map<String, dynamic>> users = [
{'name': 'John', 'age': 30},
{'name': 'Alice', 'age': 25},
{'name': 'Bob', 'age': 35}
];

// Filter users younger than 30
List<Map<String, dynamic>> youngUsers = users.where((user) => user['age'] < 30).toList();

print(youngUsers); // Output: [{'name': 'Alice', 'age': 25}]
}

2. Checking List Elements

The any method checks if any element in the list satisfies a given condition.

void main() {
List<int> numbers = [1, 2, 3, 4, 5];

// Check if any number is even
bool anyEven = numbers.any((number) => number % 2 == 0);

print(anyEven); // Output: true
}

3. Mapping Lists

Mapping lists allows you to transform each element into a new value. The map method facilitates this transformation.

void main() {
List<int> numbers = [1, 2, 3, 4, 5];

// Double each number
List<int> doubledNumbers = numbers.map((number) => number * 2).toList();

print(doubledNumbers); // Output: [2, 4, 6, 8, 10]
}

4. expand

The expand method transforms each element into an iterable and then flattens the iterable into a single list.

void main() {
List<List<int>> nestedList = [[1, 2], [3, 4], [5, 6]];

List<int> flattenedList = nestedList.expand((list) => list).toList();

print(flattenedList); // Output: [1, 2, 3, 4, 5, 6]
}

5. reduce

The reduce method applies a binary function to each element in the list to reduce the list to a single value.

void main() {
List<int> numbers = [1, 2, 3, 4, 5];

int sum = numbers.reduce((value, element) => value + element);

print(sum); // Output: 15
}

Using Flutter Widgets with Array Manipulation

Now, let’s demonstrate how to use some of these array manipulation methods to create a list of widgets using Column and ListTile in Flutter.

List of Strings

Let’s start with something easy, using a list of strings we use rray manipulation methods to create a list of widgets using Column and ListTile in Flutter.

import 'package:flutter/material.dart';

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
List<String> items = ['Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5'];

return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('List of Items'),
),
body: Column(
children: items
.map((item) => ListTile(
title: Text(item),
onTap: () {
// Handle item tap
},
))
.toList(),
),
),
);
}
}

In this Flutter example, we use the map method to transform each item in the items list into a ListTile widget. The resulting list of widgets is then passed to the children property of the Column widget, which arranges them vertically. Each ListTile represents an item in the list and can be tapped for interaction.

By combining Dart’s array manipulation methods with Flutter widgets, you can create dynamic and responsive UIs with ease. Whether you’re flattening nested lists, reducing data, or sorting elements, Dart’s array manipulation capabilities enhance your ability to build powerful Flutter applications.

In experience especially when working with dynamic data from a backend, we will be dealing with an array of objects.
Our next example: We’ll filter the list to display only the incomplete tasks in a ListView.

import 'package:flutter/material.dart';

void main() {
runApp(MyApp());
}

class Task {
final String title;
final bool completed;

Task({required this.title, required this.completed});
}

class MyApp extends StatelessWidget {
final List<Task> tasks = [
Task(title: 'Task 1', completed: true),
Task(title: 'Task 2', completed: false),
Task(title: 'Task 3', completed: false),
Task(title: 'Task 4', completed: true),
Task(title: 'Task 5', completed: false),
];

@override
Widget build(BuildContext context) {
List<Task> incompleteTasks = tasks.where((task) => !task.completed).toList();

return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Incomplete Tasks'),
),
body: ListView.builder(
itemCount: incompleteTasks.length,
itemBuilder: (context, index) {
Task task = incompleteTasks[index];
return ListTile(
title: Text(task.title),
leading: Checkbox(
value: task.completed,
onChanged: (bool? value) {
// Handle task completion
},
),
);
},
),
),
);
}
}

Alternatively and even more commonly, you can do this with a Column widget:

import 'package:flutter/material.dart';

void main() {
runApp(MyApp());
}

class Task {
final String title;
final bool completed;

Task({required this.title, required this.completed});
}

class MyApp extends StatelessWidget {
final List<Task> tasks = [
Task(title: 'Task 1', completed: true),
Task(title: 'Task 2', completed: false),
Task(title: 'Task 3', completed: false),
Task(title: 'Task 4', completed: true),
Task(title: 'Task 5', completed: false),
];

@override
Widget build(BuildContext context) {
List<Task> incompleteTasks = tasks.where((task) => !task.completed).toList();

List<Widget> taskWidgets = incompleteTasks.map((task) {
return ListTile(
title: Text(task.title),
leading: Checkbox(
value: task.completed,
onChanged: (bool? value) {
// Handle task completion
},
),
);
}).toList();

return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Incomplete Tasks'),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: taskWidgets,
),
),
),
);
}
}

Exploring Array Manipulation in Dart with Flutter

Arrays, or in Dart, lists, are fundamental data structures used extensively in programming. When working with Flutter applications, understanding how to manipulate lists efficiently is crucial for building responsive and performant UIs. Dart provides a rich set of methods for manipulating lists, allowing developers to filter, transform, and extract data with ease. In this article, we will delve into various array manipulation methods in Dart, focusing on working with lists of strings and lists of objects like Map<String, dynamic>. We'll also discuss best practices to ensure clean and efficient code.

1. Filtering Lists

Filtering lists allows you to extract elements based on specific criteria. Dart provides the where method for this purpose.

dartCopy code
void main() {
List<String> fruits = ['apple', 'banana', 'grape', 'orange', 'kiwi'];

// Filter fruits starting with 'a'
List<String> aFruits = fruits.where((fruit) => fruit.startsWith('a')).toList();

print(aFruits); // Output: [apple]
}

2. Checking List Elements

The any method checks if any element in the list satisfies a given condition.

dartCopy code
void main() {
List<int> numbers = [1, 2, 3, 4, 5];

// Check if any number is even
bool anyEven = numbers.any((number) => number % 2 == 0);

print(anyEven); // Output: true
}

3. Mapping Lists

Mapping lists allows you to transform each element into a new value. The map method facilitates this transformation.

dartCopy code
void main() {
List<int> numbers = [1, 2, 3, 4, 5];

// Double each number
List<int> doubledNumbers = numbers.map((number) => number * 2).toList();

print(doubledNumbers); // Output: [2, 4, 6, 8, 10]
}

Working with Lists of Objects

Manipulating lists of objects, such as Map<String, dynamic>, follows similar principles.

dartCopy code
void main() {
List<Map<String, dynamic>> users = [
{'name': 'John', 'age': 30},
{'name': 'Alice', 'age': 25},
{'name': 'Bob', 'age': 35}
];

// Filter users younger than 30
List<Map<String, dynamic>> youngUsers = users.where((user) => user['age'] < 30).toList();

print(youngUsers); // Output: [{'name': 'Alice', 'age': 25}]
}

Conclusion

Some of the Best Practices to keep in mind when working with arrays in your Flutter widget tree.

  1. Use Descriptive Variable Names: Make your code more readable by using descriptive names for variables and functions.
  2. Immutable Operations: Whenever possible, prefer immutable operations like where, map, and toList to avoid mutating the original list.
  3. Null Safety: With Dart’s null safety, ensure to handling of null values appropriately, especially when working with lists of objects.
  4. Performance Consideration: Be mindful of the performance implications of array manipulation operations, especially when dealing with large lists.

--

--

Emmanuel Unyime

I’m a Software Engineer && Technical Writer, I've had the TypeScript epiphany!. Oh, I play Chess too!