Sort a list of objects in Flutter (Dart) by property value
Solution 1
You can pass a comparison function to List.sort
.
someObjects.sort((a, b) => a.someProperty.compareTo(b.someProperty));
Solution 2
If you want to sort the object "objects" by the property "name" do something like this
objects.sort((a, b) {
return a.value['name'].toString().toLowerCase().compareTo(b.value['name'].toString().toLowerCase());
});
Solution 3
In general, you can provide a custom comparison function to List.sort
.
/// Desired relation | Result
/// -------------------------------------------
/// a < b | Returns a negative value.
/// a == b | Returns 0.
/// a > b | Returns a positive value.
///
int mySortComparison(SomeClass a, SomeClass b) {
final propertyA = someProperty(a);
final propertyB = someProperty(b);
if (propertyA < propertyB) {
return -1;
} else if (propertyA > propertyB) {
return 1;
} else {
return 0;
}
}
list.sort(mySortComparison);
If you're sorting some custom class you own, you alternatively could make your class implement the Comparable
interface:
class MyCustomClass implements Comparable<MyCustomClass> {
...
@override
int compareTo(MyCustomClass other) {
if (someProperty < other.someProperty) {
return -1;
} else if (someProperty > other.someProperty) {
return 1;
} else {
return 0;
}
}
}
and then you can use list.sort()
directly without supplying a callback.
Note that if you're sorting by a single property that already implements the Comparable
interface, implementing the comparison functions is much simpler. For example:
class MyCustomClass implements Comparable<MyCustomClass> {
...
@override
int compareTo(MyCustomClass other) =>
someProperty.compareTo(other.someProperty);
}
Reversing
If you want to reverse the sort order, you can make your comparison function return a value with the opposite sign. Alternatively just explicitly reverse the list after sorting:
list = (list..sort()).reversed.toList();
Sorting by multiple properties (a.k.a. subsorting)
If you want to sort by multiple properties, a general way is to perform a stable sort for each property in reverse order of importance. For example, if you want to sort names primarily by surname and then subsort within surnames by given name, then you would first sort by given names, and then perform a stable sort by surname. See below for how to perform a stable sort.
Alternatively, you could sort with a comparison function that accounts for multiple properties. For example:
class Name {
Name({String surname, String givenName})
: surname = surname ?? "",
givenName = givenName ?? "";
final String surname;
final String givenName;
}
int compareNames(Name name1, Name name2) {
var comparisonResult = name1.surname.compareTo(name2.surname);
if (comparisonResult != 0) {
return comparisonResult;
}
// Surnames are the same, so subsort by given name.
return name1.givenName.compareTo(name2.givenName);
}
Okay, I want a stable sort
List.sort
is not guaranteed to be a stable sort. If you need a stable sort, package:collection
provides insertionSort
and mergeSort
implementations that are stable.
But comparing might be expensive
Suppose you have a custom comparison function that looks something like:
int compareMyCustomClass(MyCustomClass a, MyCustomClass b) {
var a0 = computeValue(a);
var b0 = computeValue(b);
return a0.compareTo(b0);
}
Sorting might call computeValue()
on each element multiple times, which is particularly wasteful if computeValue()
is expensive. In such cases, a Schwartzian transform could be faster (at the expense of using more memory). This approach maps your objects to directly sortable keys, sorts the keys, and extracts the original objects. (This is how Python's sort
and sorted
functions work.)
Here's one possible implementation:
class _SortableKeyPair<T, K extends Comparable<Object>>
implements Comparable<_SortableKeyPair<T, K>> {
_SortableKeyPair(this.original, this.key);
final T original;
final K key;
@override
int compareTo(_SortableKeyPair<T, K> other) => key.compareTo(other.key);
}
/// Returns a sorted *copy* of [items] according to the computed sort key.
List<E> sortedWithKey<E, K extends Comparable<Object>>(
Iterable<E> items,
K Function(E) toKey,
) {
final keyPairs = [
for (var element in items) _SortableKeyPair(element, toKey(element)),
]..sort();
return [
for (var keyPair in keyPairs) keyPair.original,
];
}
void main() {
final list = <MyCustomClass>[ ... ];
final sorted = sortedWithKeys(list, computeValue);
}
Solution 4
Here is my contribution to this good question. If someone is facing difficulty to understand how the @Nate Bosch answer is working & you want to sort your custom model class list then you can do this way.
1. You have to implement Comparable
abstract class in your model class.
It has the method compareTo
which you have to override.
For example, I have this StudentMarks
model class which has marks property in it.
class StudentMarks implements Comparable {
int marks;
StudentMarks({
this.marks,
});
@override
int compareTo(other) {
if (this.marks == null || other == null) {
return null;
}
if (this.marks < other.marks) {
return 1;
}
if (this.marks > other.marks) {
return -1;
}
if (this.marks == other.marks) {
return 0;
}
return null;
}
}
2. Now you can call compareTo
method inside the sort
method.
void _sortStudents({bool reversed: false}) {
_students.sort((a, b) {
return a.compareTo(b);
});
if (reversed) {
_students = _students.reversed.toList();
}
setState(() {});
}
Refer to this link you want to know more about the Comparable
class
https://api.dart.dev/stable/2.1.0/dart-core/Comparable-class.html
Solution 5
Immutable extension sortedBy
for List.
extension MyIterable<E> on Iterable<E> {
Iterable<E> sortedBy(Comparable key(E e)) =>
toList()..sort((a, b) => key(a).compareTo(key(b)));
}
And use
list.sortedBy((it) => it.name);
Nomnom
Updated on March 07, 2022Comments
-
Nomnom about 2 years
How to sort a list of objects by the alphabetical order of one of its properties (Not the name but the actual value the property holds)?
-
Richard Heap over 5 yearsPossible duplicate of How can I sort a list of strings in Dart?
-
Nomnom over 5 years@RichardHeap yes the solution does answer my question but the question is asked differently I guess. Thanks for your help!
-
griffins over 4 yearsi wrote an answer here stackoverflow.com/a/59350472/10409567
-
-
Mahesh Jamdade about 4 yearshow do you reverse sort it
-
Nate Bosch about 4 yearsTo reverse it you could do
b.someProperty.compareTo(a.someProperty)
. Or sort it and then use.reversed
. -
Apps 247 almost 4 yearsTo reverse, just use (b,a) instead of (a,b). It's worth notinng that compareTo returns 1, 0 or -1 if you want to do more advanced sorts.
-
jasonflaherty almost 4 yearsThis is simple and easy to use for classes.
-
jamesdlin over 3 yearsIf you're sorting a list of objects that properly implements
Comparable
, you shouldn't need to explicitly callList.sort
with a callback; it should be automatic. -
Pavel Shorokhov over 3 yearsPay attention for dartx library. It is very popular and has a lot of useful extensions, mostly designed like in Kotlin.
-
Randal Schwartz about 3 yearsI was just thinking when I got to "but comparisons might be expensive" something like "I wonder how the author will approach this?" And there it was again. :)
-
Oprimus over 2 yearsThis does not provide an answer to the question. Once you have sufficient reputation you will be able to comment on any post; instead, provide answers that don't require clarification from the asker. - From Review