簡體   English   中英

按屬性值對 Flutter (Dart) 中的對象列表進行排序

[英]Sort a list of objects in Flutter (Dart) by property value

如何按其屬性之一的字母順序對對象列表進行排序(不是名稱,而是屬性所持有的實際值)?

您可以將比較函數傳遞給List.sort

someObjects.sort((a, b) => a.someProperty.compareTo(b.someProperty));

如果要按屬性“名稱”對對象“對象”進行排序,請執行以下操作

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 變換可能會更快(以使用更多內存為代價)。 這種方法將您的對象映射到可直接排序的鍵、對鍵進行排序並提取原始對象。 (這就是 Python 的sortsorted函數的工作原理。)

這是一種可能的實現:

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

List 的不可變擴展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<\/code>抽象類。<\/strong> 它具有您必須覆蓋的方法compareTo<\/code> 。 例如,我有這個StudentMarks<\/code>模型類,其中包含標記屬性。

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

在 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 }]

使用Comparator<\/code>函數,按id<\/code>對Users<\/code>進行排序。

Comparator<UserModel> sortById = (a, b) => a.id.compareTo(b.id);
users.sort(sortById);

更重要的是,您可以使用Comparable.compare更清楚,例如:

class _Person {
  final int age;
  final String name;
  _Person({required this.age, required this.name});
}

void _test() {
  final array = [
    _Person(age: 10, name: 'Dean'),
    _Person(age: 20, name: 'Jack'),
    _Person(age: 30, name: 'Ben'),
  ];

  // ascend with age
  // Dean Jack Ben
  array.sort((p1, p2) {
    return Comparable.compare(p1.age, p2.age);
  });

  // decend with age
  // Ben Jack Dean
  array.sort((p1, p2) {
    return Comparable.compare(p2.age, p1.age);
  });

  // ascend with name
  // Ben Dean Jack
  array.sort((p1, p2) {
    return Comparable.compare(p1.name, p2.name);
  });
}

類似於@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);
    }


  }

第一步:給class添加compareTo方法:

class Student {
  String? name;
  int? age;

  Student({this.name, this.age});

  int getAge() {
    if (age == null) return 0;
    return age!;
  }

  @override
  int compareTo(Student other) {
    var a = getAge();
    var b = other.getAge();

    if (a < b) {
      return -1;
    } else if (a > b) {
      return 1;
    } else {
      return 0;
    }
  }
}

第 2 步:對列表進行排序:

  • 通過升序:

    studentList.sort((a, b) { return a.compareTo(b); });

  • 通過降序:

    studentList.sort((a, b) { return b.compareTo(a); });

使用Dart靜態擴展方法對列表進行排序的示例:

import 'package:enumerable/enumerable.dart';

void main(List<String> args) {
  var strings = ["c", "bb", "b", "a", "cc", null, "aaa", 'ccc'];
  var query = strings.orderByDescending((s) => s?.length ?? 0).thenBy((s) => s);
  print(query.toList());
}

結果:

[aaa, ccc, bb, cc, a, b, c, null]

按多個屬性排序的示例(雙重排序)。

import 'package:enumerable/enumerable.dart';

void main(List<String> args) {
  final persons = [
    Person("Peter", 25),
    Person("Peter", 22),
    Person("John", 26),
    Person("Max", 26)
  ];

  final query = persons.orderBy((p) => p.name).thenBy((p) => p.age);
  print(query.toList());
}

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

結果:

[John 26, Max 26, Peter 22, Peter 25]

它對我有用:

myList..sort((a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase()));

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM