dart 如何根据两个值对列表进行排序

kmb7vmvb  于 9个月前  发布在  其他
关注(0)|答案(6)|浏览(63)

我有一个列表,我想根据两个值date和status进行排序,如下所示:

pollsList.sort((a, b) => b.active.compareTo(a.active));

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

字符串
其中active == 90表示它是active的,-90表示它不是。
我想根据日期对列表进行排序,然后根据日期进行排序。
我希望最新的顶部和总是关闭后的活动项目。
但是这将导致列表只按日期排序。我如何按两个值排序?

yuvru6vn

yuvru6vn1#

您希望对列表进行排序,以便较晚的开始时间排序在较早的开始时间之前,如果两个元素具有相同的开始时间,则将活动元素排序在非活动元素之前。
你尝试的是对列表进行两次排序。这只有在排序算法是 stable 的情况下才有效,也就是说,如果等于wrt的元素。第二次排序比较保持第一次排序时的顺序。Dart的排序并不保证是稳定的,所以这不是一个安全的方法。即使它看起来有效,很可能有一种排序算法对于较小的列表是稳定的,而对于较大的列表则不稳定。
你应该做的是创建一个单一的比较函数,一次完成两个比较。首先比较开始时间。如果它们不相等,你就完成了,否则也比较活动。

pollsList.sort((a, b) {
  int cmp = b.actualStartDatetime.compareTo(a.actualStartDatetime);
  if (cmp != 0) return cmp;
  return b.active.compareTo(a.active);
});

字符串
如果您希望所有非活动元素在所有活动元素之前排序,然后按开始时间对这些组中的每个组进行排序,则按相反的顺序进行比较:

pollsList.sort((a, b) {
  int cmp = b.active.compareTo(a.active);
  if (cmp != 0) return cmp;
  return b.actualStartDatetime.compareTo(a.actualStartDatetime);
});

odopli94

odopli942#

我通过将两列合并为一列来解决这个问题。“${a.active}${a.actualStartDatetime}”并将其与b进行比较。

data.sort((a, b) =>  ("${a.active}${a.actualStartDatetime}").toString()
.compareTo(("${b.status}${b.actualStartDatetime.toUpperCase()}").toString()));

字符串

gz5pxeao

gz5pxeao3#

这不是最优雅的,但它相当直接,对我来说很有效:
1.根据第一个排序标准将您的原始列表划分为2个新列表;
1.按照第二个标准对每个新列表进行排序;
1.最后,合并将这两个新列表组合成一个最终的排序列表;
举例来说:

List<Polls> activePollsList;
    List<Polls> inactivePollsList;
    List<Polls> finalSortedPollsList;
    
    activePollsList.addAll(pollsList.where((Poll poll) => poll.isActive == true));
    activePollsList.sort((a, b) => a.actualStartDateTime.compareTo(b.actualStartDateTime));
    
    inactivePollsList.addAll(pollsList.where((Polls poll) => poll.isActive == false));
    inactivePollsList.sort((a, b) => a.actualStartDateTime.compareTo(b.actualStartDateTime));
    
    finalSortedPollsList = activePollsList + inActivePollsList;

字符串
finalSortedList将保留两个列表所做的排序。
请注意,在上面我假设您的pollsList是一个名为Polls的自定义对象列表,但您可能希望将上面代码中的Poll更改为您的自定义对象的名称。
同样,这不是最优雅的解决方案,但在Dart允许多个排序标准之前,这对我来说是有效的。

ego6inou

ego6inou4#

基于两个或多个条件对列表进行排序的一种更通用的方法是使用comparator function
可用于Dart列表的sort方法接受comparator函数作为可选参数。
在下面的例子中,一个列表的条目类型为MyWidget(具有属性:titletimestatus),以不同的方式排序,而不需要创建和合并单独的列表。

/// The current status of the widget.
enum Status { open, closed }

// A comparator function for object of type `Status`.
int statusComparator(left, right) {
  if (left == right) return 0;
  if (left == Status.open) return -1;
  return 1;
}

/// DateTime Comparator based on year-month-day  only.
int timeComparator(left, right) {
  var result = -left.year.compareTo(right.year);
  result = result == 0 ? -left.month.compareTo(right.month) : result;
  result = result == 0 ? -left.day.compareTo(right.day) : result;
  return result;
}

/// Sample Widget Class
/// Implements Comparable and requires a `compareTo` method. 
class MyWidget implements Comparable {
  MyWidget(this.title, {this.status = Status.open}) : time = DateTime.now();

  late DateTime time;
  String title;
  Status status;

  @override
  String toString() {
    return '$title ${time.day}-${time.month}-${time.year} ${status.name}';
  }

  /// Default method used for sorting by title > time > status.
  @override
  int compareTo(other) {
    int result = title.compareTo(other.title);
    result = result == 0 ? timeComparator(time, other.time) : result;
    result = result == 0 ? statusComparator(status, other.status) : result;
    return result;
  }

  /// Additional comparator used for sorting by status > time > title.
  static int openFirstComparator<T extends MyWidget>(T left, T right) {
    var result = statusComparator(left.status, right.status);
    result = result == 0 ? timeComparator(left.time, right.time) : result;
    return result == 0 ? left.title.compareTo(right.title) : result;
  }
}

void main() {
  var list = [
    MyWidget('Carol', status: Status.closed)..time = DateTime(2018),
    MyWidget('Carol')..time = DateTime(2018),
    MyWidget('Carol')
      ..time = DateTime(2022)
      ..status = Status.closed,
    MyWidget('Bernard')..time = DateTime(2020),
    MyWidget('Anne'),
    MyWidget('Anne', status: Status.closed),
    MyWidget('Bernard', status: Status.closed),
  ];

  /// Default sorting by title > date > status using the `compareTo` method.
  print('Sorted by title > date > status');
  print(list..sort());

  print('');

  /// Sorted by status, date and title using a custom comparator.
  print('Sorted by status > date > title');
  print(list..sort(MyWidget.openFirstComparator));
}

字符串
运行程序将显示:

$ dart main.dart
Sorted by title > date > status
[Anne 2-3-2022 open, Anne 2-3-2022 closed, Bernard 2-3-2022 closed, Bernard 1-1-2020 open, Carol 1-1-2022 closed, Carol 1-1-2018 open, Carol 1-1-2018 closed]

Sorted by status > date > title
[Anne 2-3-2022 open, Bernard 1-1-2020 open, Carol 1-1-2018 open, Anne 2-3-2022 closed, Bernard 2-3-2022 closed, Carol 1-1-2022 closed, Carol 1-1-2018 closed]


提示:要快速运行代码,请复制并粘贴到dartpad编辑器中。

qhhrdooz

qhhrdooz5#

我有一个相当简单的多个字段排序的解决方案,将它们连接到一个很长的字符串中,然后它们会自己排序。

listOpenOrders.sort(((a, b) {
      return ("${a.deliveryDate?.millisecondsSinceEpoch}${a.customerName}${a.itemCode}")
          .compareTo(
              "${b.deliveryDate?.millisecondsSinceEpoch}${b.customerName}${b.itemCode}");
    }));

字符串

bakd9h0s

bakd9h0s6#

为了增加这里的答案,我向您提供了一个通用的解决方案,可以为您可能拥有的任何模型按 * 无限 * 数量的属性进行排序。
我将首先从使用它的外观开始:

pollsList.sort(multiPropertyCompare([
        ((t) => t.actualStartDatetime, ascending: true),
        ((t) => t.active, ascending: false),
        // You can add all the properties you need...
        ((t) => t.somethingElse, ascending: true),
        ((t) => t.yetAnotherProperty, ascending: false),
      ]));

字符串
这就是:

int Function(T, T) multiPropertyCompare<T>(
  List<(Comparable<Object?> Function(T), {bool ascending})> properties,
) {
  return (T a, T b) {
    for (final (propertyExtractor, :ascending) in properties) {
      final (x, y) = ascending ? (a, b) : (b, a);
      final result = propertyExtractor(x).compareTo(propertyExtractor(y));
      if (result != 0) {
        return result;
      }
    }
    return 0;
  };
}


如果你需要自己调用这个函数(而不是把它传递给sort方法),它看起来像这样。下面是一个实现ComparablecompareTo方法的例子。注意你需要添加类型参数!

@override
int compareTo(Transaction other) {
  return multiPropertyCompare<Transaction>([ // <- Type argument here!
    ((t) => t.date, ascending: true),
    ((t) => t.destinationId, ascending: true),
    ((t) => t.sourceId, ascending: true),
    ((t) => t.amount, ascending: true),
    ((t) => t.fee, ascending: true),
    ((t) => t.type, ascending: true),
  ])(this, other);
}

相关问题