Understanding Dart Lists
Dart's List, often cmopared to arrays in other languages like JavaScript, offers distinct characteristics. A key distinction is the concept of fixed-length versus growable lists. Let's explore this difference with an example:
// Declare a fixed-length list
List<int> immutableList = List<int>.filled(5, 0); // Creates a list of length 5
// immutableList.length = 3; // This would cause an error: cannot change length
// immutableList.add(10); // This would cause an error: cannot add to a fixed-length list
immutableList[2] = 42; // Modifying an existing element is allowed
// Declare a growable list
List<string> mutableList = ['apple', 'banana'];
mutableList.length = 0; // This is allowed, it clears the list
print(mutableList); // Output: []
mutableList.add('cherry');
mutableList.add('date');
mutableList[0] = 'apricot';
print(mutableList); // Output: [apricot, date]
</string></int></int>
As demonstrated, when a list is initialized with a specific length (e.g., using List.filled or the deprecated List(5)), its size becomes immutable. Operations that alter the length will fail. Conversely, lists created with a literal syntax ([]) or the default constructor (List()) are growable by default.
List Construction
Dart provides several constructor to create lists with different initial states.
Basic Constructors
// A fixed-length list of 4 null elements
var fixedList = List<int>(4);
// fixedList.length = 5; // Error: cannot change length
// A growable, empty list
var growableList = List<string>();
growableList.length = 6; // OK
</string></int>
List.filled
This constructor creates a list of a given length, where every element is initialized to the provided value. Be cautious with non-primitive objects, as the same reference is used for all elements.
// A list of three zeros
var numbers = List<int>.filled(3, 0); // [0, 0, 0]
// A list of three string references
var stringRefs = List<string>.filled(3, 'initial');
stringRefs[1] = 'changed';
print(stringRefs); // ['initial', 'changed', 'initial']
// A list of three map references
var mapRefs = List<map>.filled(3, {});
mapRefs[0]['key'] = 'value';
print(mapRefs); // [{key: value}, {key: value}, {key: value}]
</map></string></int>
List.generate
This constructor generates elements by calling a provided function for each index.
// Generate a list of squares: [0, 1, 4, 9, 16]
var squares = List<int>.generate(5, (index) => index * index);
</int>
List.from
This constructor creates a list from any Iterable object. An optional growable parameter can be set to false to create a fixed-length list.
// Create a list from a Set
var sourceSet = {10, 20, 30};
var fromSet = List<int>.from(sourceSet);
print(fromSet); // Output may vary, e.g., [10, 20, 30]
// Create an unmodifiable list from another list
var original = [1, 2, 3];
var unmodifiable = List<int>.unmodifiable(original);
// unmodifiable.add(4); // This would cause an error
</int></int>
List Properties
Lists have several useful properties for quick access to common information.
var colors = ['red', 'green', 'blue'];
print(colors.first); // 'red'
print(colors.last); // 'blue'
print(colors.length); // 3
print(colors.reversed); // (blue, green, red) - an Iterable
print(List.from(colors.reversed)); // ['blue', 'green', 'red']
List Instance Methods
List methods can be categorized by their primary operation: adding, removing, modifying, querying, and transforming data.
Adding Elements
add(element): Appends a single element.addAll(elements): Appends all elements from an iterable.insert(index, element): Inserts an element at a specific position.insertAll(index, elements): Inserts multiple elements at a specific position.
var fruits = <string>[];
fruits.add('orange');
print(fruits); // [orange]
fruits.addAll(['pear', 'kiwi']);
print(fruits); // [orange, pear, kiwi]
fruits.insert(1, 'apple');
print(fruits); // [orange, apple, pear, kiwi]
fruits.insertAll(2, ['mango', 'peach']);
print(fruits); // [orange, apple, mango, peach, pear, kiwi]
</string>
Removing Elements
clear(): Removes all elements.remove(element): Removes the first occurrence of an element.removeAt(index): Removes the element at a specific index.removeLast(): Removes the last element.removeRange(start, end): Removes a range of elements.removeWhere(test): Removes all elements that satisfy a condition.retainWhere(test): Keeps only elements that satisfy a condition.
var numbers = List.generate(50, (i) => i); // [0, 1, ..., 49]
numbers.removeLast(); // Removes 49
numbers.removeAt(10); // Removes the element at index 10 (value 10)
numbers.remove(25); // Removes the first occurrence of 25
numbers.removeRange(20, 30); // Removes elements from index 20 to 29
print(numbers.length); // 38
numbers.removeWhere((n) => n > 40); // Removes numbers greater than 40
numbers.retainWhere((n) => n.isEven); // Keeps only even numbers
print(numbers); // e.g., [0, 2, 4, 6, 8, 12, 14, 16, 18, 22, 24, 26, 28, 32, 34, 36, 38]
numbers.clear();
print(numbers); // []
Modifying Elements
setAll(index, iterable): Overwrites elements starting atindexwith elements fromiterable.setRange(start, end, iterable, [startFrom]): Copies a range of elements fromiterableinto the list.replaceRange(start, end, replacement): Replaces a range of elements with elements fromreplacement.
// setAll example
List<string> letters = ['a', 'b', 'c', 'd'];
letters.setAll(1, ['bee', 'sea']);
print(letters.join(', ')); // a, bee, sea, d
// setRange example
List<int> source = [10, 20, 30, 40, 50];
List<int> target = [1, 2, 3, 4];
target.setRange(1, 3, source, 2); // Copies from source[2] and source[3] into target[1] and target[2]
print(target.join(', ')); // 1, 30, 40, 4
// replaceRange example
List<int> data = [100, 200, 300, 400, 500];
data.replaceRange(1, 4, [999]);
print(data.join(', ')); // 100, 999, 500
</int></int></int></string>
Querying Elements
indexOf(element, [start]): Finds the first index of an element.lastIndexOf(element, [start]): Finds the last index of an element.indexWhere(test, [start]): Finds the first index where a test passes.lastIndexWhere(test, [start]): Finds the last index where a test passes.
var items = [5, 15, 25, 15, 35];
print(items.indexOf(15)); // 1
print(items.lastIndexOf(15)); // 3
print(items.indexWhere((item) => item > 20)); // 2
print(items.lastIndexWhere((item) => item < 30)); // 3
Sorting and Shuffling
sort([compare]): Sorts the list in-place.shuffle([random]): Randomly reorders the list in-place.
var values = [88, 17, 55, 2, 41, 93];
values.sort((a, b) => a.compareTo(b)); // Ascending sort
print(values); // [2, 17, 41, 55, 88, 93]
values.shuffle();
print(values); // e.g., [41, 2, 88, 93, 17, 55]