138

How do you get the min and max values of a List in Dart.

[1, 2, 3, 4, 5].min //returns 1
[1, 2, 3, 4, 5].max //returns 5

I'm sure I could a) write a short function or b) copy then sort the list and select the last value,

but I'm looking to see if there is a more native solution if there is any.

basheps
  • 10,034
  • 11
  • 36
  • 45

9 Answers9

238

Assuming the list is not empty you can use Iterable.reduce :

import 'dart:math';

main(){
  print([1,2,8,6].reduce(max)); // 8
  print([1,2,8,6].reduce(min)); // 1
}
ThinkDigital
  • 3,189
  • 4
  • 26
  • 34
Alexandre Ardhuin
  • 71,959
  • 15
  • 151
  • 132
65

If you don't want to import dart: math and still wants to use reduce:

main() {
  List list = [2,8,1,6]; // List should not be empty.
  print(list.reduce((curr, next) => curr > next? curr: next)); // 8 --> Max
  print(list.reduce((curr, next) => curr < next? curr: next)); // 1 --> Min
}
kk.
  • 3,747
  • 12
  • 36
  • 67
  • Why would one seriously prefer this approach? – Mateus Felipe Dec 19 '19 at 20:54
  • @MateusFelipe You can pass this as a Function, where as with math.max or min I ran into some trouble. – onesiumus Jan 26 '20 at 04:01
  • Well, then it would be a good idea providing the specific use-case of your approach, as it seems to be a very edge case. – Mateus Felipe Jan 27 '20 at 08:51
  • 24
    This actually is a useful comment. Whenever the list is List of Objects rather than List of (String, Number) we can't directly use dart:math. We have to do something like "curr.id < next.id" etc. – Kavinda Jayakody Feb 18 '20 at 13:46
  • 1
    Exactly, it is totally useful. For example, I used this for DateTime: `dates.reduce((current, next) => current.compareTo(next) > 0 ? current : next)` Closest thing to LINQ-like syntax. – jnt Jun 09 '20 at 14:44
  • 1
    @KavindaJayakody You can do this using myList.map((e) => e.myNumber).reduce(max) – kozenka Mar 26 '21 at 21:11
  • This answers provides the most flexible and clear solution to the problem. It's also a great use of the .reduce paradigm. – dingo Oct 21 '22 at 07:52
  • @KavindaJayakody For a list of objects I'd suggest [`minBy()`](https://pub.dev/documentation/collection/latest/collection/minBy.html)/[`maxBy()`](https://pub.dev/documentation/collection/latest/collection/maxBy.html) from [collection package](https://pub.dev/packages/collection). – Chuck Batson Dec 20 '22 at 19:06
  • @kozenka Nice. You should put that as one of the answers. – Giraldi Jun 05 '23 at 09:05
36

You can now achieve this with an extension as of Dart 2.6:

import 'dart:math';

void main() {
  [1, 2, 3, 4, 5].min; // returns 1
  [1, 2, 3, 4, 5].max; // returns 5
}

extension FancyIterable on Iterable<int> {
  int get max => reduce(math.max);

  int get min => reduce(math.min);
}
creativecreatorormaybenot
  • 114,516
  • 58
  • 291
  • 402
9

An example to get Min/Max value using reduce based on condition for a list of Map objects

Map studentA = {
  'Name': 'John',
  'Marks': 85
};

Map studentB = {
  'Name': 'Peter',
  'Marks': 70
};

List<Map> students = [studentA, studentB];

// Get student having maximum mark from the list

Map studentWithMaxMarks = students.reduce((a, b) {
    if (a["Marks"] > b["Marks"])
        return a;
    else
        return b;
});


// Get student having minimum mark from the list (one liner)

Map studentWithMinMarks = students.reduce((a, b) => a["Marks"] < b["Marks"] ? a : b);

Another example to get Min/Max value using reduce based on condition for a list of class objects

class Student {
    final String Name;
    final int Marks;

    Student(this.Name, this.Marks);
}

final studentA = Student('John', 85);
final studentB = Student('Peter', 70);

List<Student> students = [studentA, studentB];

// Get student having minimum marks from the list

Student studentWithMinMarks = students.reduce((a, b) => a.Marks < b.Marks ? a : b);
Abdul Saleem
  • 10,098
  • 5
  • 45
  • 45
7

If your list is empty, reduce will throw an error.

You can use fold instead of reduce.

// nan compare to any number will return false
final initialValue = number.nan;
// max
values.fold(initialValue, (previousValue, element) => element.value > previousValue ? element.value : previousValue);
// min
values.fold(initialValue, (previousValue, element) => element.value < previousValue ? element.value : previousValue);

It can also use to calculate sum.

final initialValue = 0;
values.fold(initialValue, (previousValue, element) => element.value + previousValue);

Although fold is not cleaner than reduce for getting min/max, it is still a powerful method to do more flexible actions.

呂學洲
  • 1,123
  • 8
  • 19
4
void main() {
  firstNonConsecutive([1,2,3,4,6,7,8]);
}

int? firstNonConsecutive(List<int> arr) {
  var max = arr.reduce((curr, next) => curr > next? curr: next);
  print(max); // 8 --> Max
  var min = arr.reduce((curr, next) => curr < next? curr: next);
  print(min); // 1 --> Min
  return null;
}
Jamirul islam
  • 502
  • 6
  • 10
3

For empty lists: This will return 0 if list is empty, the max value otherwise.

  List<int> x = [ ];  
  print(x.isEmpty ? 0 : x.reduce(max)); //prints 0

  List<int> x = [1,32,5];  
  print(x.isEmpty ? 0 : x.reduce(max)); //prints 32
lenz
  • 2,193
  • 17
  • 31
2
int minF() {
  final mass = [1, 2, 0, 3, 5];
  mass.sort();
  
  return mass[0];
}
Kley
  • 93
  • 1
  • 1
  • 8
  • You could also use the list.first or list.last property to achieve a min and max without using the index. – dingo Oct 21 '22 at 07:40
  • 1
    Note that the time complexity of a sort is generally `O(n log n)` whereas min and max are `O(n)`. – Chuck Batson Nov 10 '22 at 21:29
2

If you need a more sophisticated min/max, such as finding an object with a min/max of a field, or use of a comparison predicate, use minBy() and maxBy() from the collection package:

import 'package:collection/collection.dart';

class Person {
  final String name;
  final int age;
  
  Person(this.name, this.age);
  
  @override
  String toString() => '$name (age $age)';
}

main() {
  final alice = Person('Alice', 30);
  final bob = Person('Bob', 40);
  final chris = Person('Chris', 25);
  final dan = Person('Dan', 35);
  
  final people = [alice, bob, chris, dan];
  
  print('Youngest is ${minBy(people, (e) => e.age)}');
  print('Oldest is ${maxBy(people, (e) => e.age)}');
  print('First alphabetically is ${minBy(people, (e) => e.name)}');
  print('Last alphabetically is ${maxBy(people, (e) => e.name)}');
  
  print('Largest name length times age is ${maxBy(people, (e) => e, compare: (a, b) => (a.name.length * a.age).compareTo(b.name.length * b.age))}');
}

Output:

Youngest is Chris (age 25)
Oldest is Bob (age 40)
First alphabetically is Alice (age 30)
Last alphabetically is Dan (age 35)
Largest name length times age is Alice (age 30)
Chuck Batson
  • 2,165
  • 1
  • 17
  • 15