【问题标题】:Sort a list of objects in Flutter (Dart) by property value按属性值对 Flutter (Dart) 中的对象列表进行排序
【发布时间】:2020-03-08 17:58:29
【问题描述】:

如何按其中一个属性的字母顺序对对象列表进行排序(不是名称,而是属性所包含的实际值)?

【问题讨论】:

标签: list flutter sorting dart


【解决方案1】:

您可以将比较函数传递给List.sort

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

【讨论】:

  • 如何反向排序
  • 要扭转它,你可以做b.someProperty.compareTo(a.someProperty)。或者排序然后使用.reversed
  • 要反转,只需使用 (b,a) 而不是 (a,b)。值得注意的是,如果您想进行更高级的排序,compareTo 返回 1、0 或 -1。
【解决方案2】:

如果您想按属性“名称”对对象“对象”进行排序,请执行以下操作

objects.sort((a, b) {
  return a.value['name'].toString().toLowerCase().compareTo(b.value['name'].toString().toLowerCase());
});    

【讨论】:

    【解决方案3】:

    一般情况下,您可以为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 提供了稳定的 insertionSortmergeSort 实现。


    但比较可能会很昂贵

    假设您有一个看起来像这样的自定义比较函数:

    int compareMyCustomClass(MyCustomClass a, MyCustomClass b) {
      var a0 = computeValue(a);
      var b0 = computeValue(b);
      return a0.compareTo(b0);
    }
    

    排序可能会在每个元素上多次调用computeValue(),如果computeValue() 很昂贵,这尤其浪费。在这种情况下,Schwartzian transform 可能会更快(以使用更多内存为代价)。这种方法将您的对象映射到可直接排序的键、对键进行排序并提取原始对象。 (这就是 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);
    }
    

    【讨论】:

    • 当我想到“但比较可能很昂贵”时,我只是在想“我想知道作者将如何处理这个问题?”它又来了。 :)
    【解决方案4】:

    不可变扩展 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);
    

    【讨论】:

    • 关注 dartx 库。它非常流行并且有很多有用的扩展,大部分都像 Kotlin 一样设计。
    【解决方案5】:

    这是我对这个好问题的贡献。如果有人难以理解@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;它应该是自动的。
    【解决方案6】:

    在 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) =&gt; a.age.compareTo(b.age)); 完美运行!
    【解决方案7】:

    使用Comparatorfunction,将Usersid排序。

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

    现在我们可以按倒序/降序对其进行排序。

    users = users.reversed.toList();
    

    【讨论】:

    • 这是简单易用的类。
    【解决方案8】:

    类似于@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;
    
    }
    

    【讨论】:

      【解决方案9】:

      逆序排列:

      list.sort((a, b) {
                return b.status.toLowerCase().compareTo(a.status.toLowerCase());
              });
      

      【讨论】:

        【解决方案10】:

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

        【讨论】:

          【解决方案11】:

          它对我有用:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-02-12
            • 2023-04-03
            • 2016-02-08
            • 1970-01-01
            相关资源
            最近更新 更多