【发布时间】:2020-03-08 17:58:29
【问题描述】:
如何按其中一个属性的字母顺序对对象列表进行排序(不是名称,而是属性所包含的实际值)?
【问题讨论】:
-
@RichardHeap 是的,该解决方案确实回答了我的问题,但我猜这个问题的问法不同。感谢您的帮助!
-
我在这里写了一个答案stackoverflow.com/a/59350472/10409567
如何按其中一个属性的字母顺序对对象列表进行排序(不是名称,而是属性所包含的实际值)?
【问题讨论】:
您可以将比较函数传递给List.sort。
someObjects.sort((a, b) => a.someProperty.compareTo(b.someProperty));
【讨论】:
b.someProperty.compareTo(a.someProperty)。或者排序然后使用.reversed。
如果您想按属性“名称”对对象“对象”进行排序,请执行以下操作
objects.sort((a, b) {
return a.value['name'].toString().toLowerCase().compareTo(b.value['name'].toString().toLowerCase());
});
【讨论】:
一般情况下,您可以为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);
如果您要对您拥有的一些自定义类进行排序,您也可以让您的类实现Comparable 接口:
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;
}
}
}
然后您可以直接使用list.sort(),而无需提供回调。
请注意,如果您按已实现Comparable 接口的单个属性进行排序,则实现比较函数要简单得多。例如:
class MyCustomClass implements Comparable<MyCustomClass> {
...
@override
int compareTo(MyCustomClass other) =>
someProperty.compareTo(other.someProperty);
}
如果你想反转排序顺序,你可以让你的比较函数返回一个带有相反符号的值。或者,只需在排序后显式反转列表:
list = (list..sort()).reversed.toList();
如果要按多个属性排序,一般的方法是对每个属性按重要性相反的顺序执行稳定排序。例如,如果您想主要按姓氏对姓名进行排序,然后在姓氏中按给定的名字进行子排序,那么您将首先按给定的名字排序,然后按姓氏执行稳定的排序。请参阅下文了解如何执行稳定排序。
或者,您可以使用包含多个属性的比较函数进行排序。例如:
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);
}
List.sort 不保证是稳定的排序。如果您需要稳定的排序,package:collection 提供了稳定的 insertionSort 和 mergeSort 实现。
假设您有一个看起来像这样的自定义比较函数:
int compareMyCustomClass(MyCustomClass a, MyCustomClass b) {
var a0 = computeValue(a);
var b0 = computeValue(b);
return a0.compareTo(b0);
}
排序可能会在每个元素上多次调用computeValue(),如果computeValue() 很昂贵,这尤其浪费。在这种情况下,Schwartzian transform 可能会更快(以使用更多内存为代价)。这种方法将您的对象映射到可直接排序的键、对键进行排序并提取原始对象。 (这就是 Python 的 sort 和 sorted 函数的工作原理。)
这是一种可能的实现方式:
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);
}
【讨论】:
不可变扩展 sortedBy 用于列表。
extension MyIterable<E> on Iterable<E> {
Iterable<E> sortedBy(Comparable key(E e)) =>
toList()..sort((a, b) => key(a).compareTo(key(b)));
}
并使用
list.sortedBy((it) => it.name);
【讨论】:
这是我对这个好问题的贡献。如果有人难以理解@Nate Bosch 的答案是如何工作的,并且您想对自定义模型类列表进行排序,那么您可以这样做。
1.您必须在模型类中实现 Comparable 抽象类。
它具有您必须覆盖的方法compareTo。
例如,我有这个 StudentMarks 模型类,其中包含标记属性。
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。现在您可以在sort 方法中调用compareTo 方法。
void _sortStudents({bool reversed: false}) {
_students.sort((a, b) {
return a.compareTo(b);
});
if (reversed) {
_students = _students.reversed.toList();
}
setState(() {});
}
如果您想了解更多关于Comparable 类的信息,请参阅此链接
https://api.dart.dev/stable/2.1.0/dart-core/Comparable-class.html
【讨论】:
Comparable 的对象列表进行排序,则不需要通过回调显式调用List.sort;它应该是自动的。
在 Dart/Flutter 中对对象列表进行排序
1使用自定义比较功能:
class Customer {
String name;
int age;
Customer(this.name, this.age);
@override
String toString() {
return '{ ${this.name}, ${this.age} }';
}
}
main() {
List customers = [];
customers.add(Customer('Jack', 23));
customers.add(Customer('Adam', 27));
customers.add(Customer('Katherin', 25));
customers.sort((a, b) => a.age.compareTo(b.age));
print('Sort by Age: ' + customers.toString());
customers.sort((a, b) => a.name.compareTo(b.name));
print('Sort by Name: ' + customers.toString());
}
输出:
Sort by Age: [{ Jack, 23 }, { Katherin, 25 }, { Adam, 27 }]
Sort by Name: [{ Adam, 27 }, { Jack, 23 }, { Katherin, 25 }]
2 第二种方法是扩展Comparable抽象类并覆盖compareTo()方法。现在我们不需要传递比较函数,我们只需调用list.sort() 而不是list.sort(compare)。
class Customer extends Comparable {
String name;
int age;
Customer(this.name, this.age);
@override
String toString() {
return '{ ${this.name}, ${this.age} }';
}
// sort by Name (asc), then age (desc)
@override
int compareTo(other) {
int nameComp = this.name.compareTo(other.name);
if (nameComp == 0) {
return -this.age.compareTo(other.age); // '-' for descending
}
return nameComp;
}
}
main() {
List customers = [];
customers.add(Customer('Jack', 23));
customers.add(Customer('Adam', 27));
customers.add(Customer('Katherin', 25));
customers.add(Customer('Jack', 32));
customers.sort();
print(customers);
}
输出:
[{ Adam, 27 }, { Jack, 32 }, { Jack, 23 }, { Katherin, 25 }]
【讨论】:
customers.sort((a, b) => a.age.compareTo(b.age)); 完美运行!
使用Comparatorfunction,将Users按id排序。
Comparator<UserModel> sortById = (a, b) => a.id.compareTo(b.id);
users.sort(sortById);
现在我们可以按倒序/降序对其进行排序。
users = users.reversed.toList();
【讨论】:
类似于@pavel-shorokhovs 的答案,但强类型:
extension IterableExtensions<T> on Iterable<T> {
Iterable<T> sortBy<TSelected extends Comparable<TSelected>>(
TSelected Function(T) selector) =>
toList()..sort((a, b) => selector(a).compareTo(selector(b)));
Iterable<T> sortByDescending<TSelected extends Comparable<TSelected>>(
TSelected Function(T) selector) =>
sortBy(selector).toList().reversed;
}
【讨论】:
逆序排列:
list.sort((a, b) {
return b.status.toLowerCase().compareTo(a.status.toLowerCase());
});
【讨论】:
我有 fpgrowth 机器学习输出/结果,列表的每个元素都包含另一个列表和频率字段,我将按频率降序排序,所以我使用了一些递归来尝试它可能会起作用我知道我迟到了,但是我在发帖,也许其他人可以从中受益。
sort(List<FrequentItem> fqItems) {
int len = fqItems.length;
if(len==2){
if(fqItems[0].frequency>fqItems[1].frequency){
sortedItems.add(fqItems[0]);
sortedItems.add(fqItems[1]);
}else{
sortedItems.add(fqItems[1]);
sortedItems.add(fqItems[0]);
}
return;
}else{
FrequentItem max = fqItems[0];
int index =0;
for(int i=0;i<len-2;i++){
if(max.frequency<fqItems[i+1].frequency){
max = fqItems[i+1];
index = i+1;
}
}
sortedItems.add(max);
fqItems.removeAt(index);
sort(fqItems);
}
}
【讨论】:
它对我有用:
myList..sort((a, b) => a.sortFactor.compareTo(b.sortFactor));
【讨论】: