Dart列表的最小/最大值

138

如何在Dart中获取List的最小值和最大值。

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

我相信我可以 a) 写一个简短的函数或者 b) 复制并排序列表然后选择最后一个值,

但是我正在寻找是否有更本地的解决方案。

9个回答

242

假设该列表不为空,则可以使用Iterable.reduce

import 'dart:math';

main(){
  print([1,2,8,6].reduce(max)); // 8
  print([1,2,8,6].reduce(min)); // 1
}

1
如果列表可能为空,我该怎么办?有没有避免检查空的方法? - Alex Semeniuk
5
你可以使用 [maxOnEmpty, ...list].reduce(max) - Alexandre Ardhuin
16
谢谢,但我已经找到了更简洁的解决方案。[1,2,8,6].fold(0, max) 就能达到效果。 - Alex Semeniuk
1
看起来这在空列表上仍然无法运行... 例如[].fold(0,max)会抛出错误。@AlexSemeniuk - PROgram52bc
1
@PROgram52bc 你确定已经正确指定了列表类型吗? - Alex Semeniuk
@AlexSemeniuk 您的解决方案完美:int biggestNum(List<int> numbers) => numbers.fold(0, max); - Richard Sipher

67

如果您不想导入dart:math但仍希望使用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
}

为什么有人会认真地偏爱这种方法? - Mateus Felipe
24
这个评论实际上很有用。如果列表是对象列表而不是字符串和数字的列表,我们就不能直接使用dart:math。我们需要做类似于“curr.id < next.id”等操作。 - Kavinda Jayakody
1
确切地说,它非常有用。例如,我在DateTime中使用了这个:dates.reduce((current, next) => current.compareTo(next) > 0 ? current : next) 最接近LINQ语法的东西。 - jnt
1
@KavindaJayakody 你可以使用myList.map((e) => e.myNumber).reduce(max)来实现这个功能。 - kozenka
这个答案提供了问题最灵活和清晰的解决方案。它还是.reduce范例的一个很好的应用。 - dingo
显示剩余6条评论

36

现在,您可以使用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);
}

很棒,使用as关键字在导入语句中可以为我解决问题。import 'dart:math' as math; - someone

9
使用reduce基于条件获取Map对象列表中的最小/最大值示例
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);

使用reduce基于条件获取类对象列表的最小/最大值的另一个示例

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);

7
如果你的列表为空,reduce 将会抛出一个错误。
你可以使用 fold 来代替 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);

它还可以用于计算总和。

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

虽然 fold 在获取最小/最大值方面不如 reduce 清晰,但它仍然是一个执行更灵活操作的强大方法。


3
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;
}

3

对于空列表:如果列表为空,将返回0,否则返回最大值。

  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

2
如果您需要更复杂的最小/最大值,例如查找具有字段最小/最大值的对象,或使用比较谓词,请使用minBy()maxBy()功能来自collection包
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))}');
}

输出:

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)

1
很好。这个方法更加直接。 - hanswim
如果集合中有多个具有相同最大/最小值的对象,而我需要所有这些对象呢? - undefined
@ivanesi 很抱歉,我并不完全理解。你能提供更多细节吗?或者,考虑创建一个新问题并在其中标记我,随时都可以。 - undefined

2
int minF() {
  final mass = [1, 2, 0, 3, 5];
  mass.sort();
  
  return mass[0];
}

你也可以使用list.first或list.last属性来实现最小值和最大值,而不需要使用索引。 - dingo
1
请注意,排序的时间复杂度通常为O(n log n),而最小值和最大值为O(n) - Chuck Batson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接