在Dart/Flutter中如何按日期对列表进行排序?

93
我有一个列表,需要按照日期时间重新排序。
import 'package:intl/intl.dart'; 
//don't forget to add under dependencies pubspec.yml "intl: ^0.15.8"


List products = [];

//adding into the new list from raw API list
for(final item in rawProducts){

   var parsedDate = DateTime.parse.(item['expiryDate']);
   tmpArray = {
     'id': item['id'],
     'name': item['name'],
     'price': item['price'],
     'expiry': parsedDate
   }
   products.add(tmpArray);
  }
}


List products = [

 {id: 1242, name: milk, price: $5, expiry: 2019-11-25 00:00:00:000},
 {id: 1242, name: egg, price: $2, expiry: 2019-11-22 00:00:00:000},
 {id: 1243, name: bread, price: $3, expiry: 2019-11-22 00:00:00:000},
 {id: 1244, name: butter, price: $7, expiry: 2019-11-24 00:00:00:000},
 {id: 1247, name: butter, price: $7, expiry: 2019-11-23 00:00:00:000},

]

我想以最晚的到期日期为先重新排序列表:
 25-11-2019
 24-11-2019
 23-11-2019
 22-11-2019
 22-11-2019

我尝试过的方法(更新)-> 通过将 a.expiry 更改为 a ['expiry'] 解决:
  products.sort((a,b) {
    var adate = a['expiry'] //before -> var adate = a.expiry;
     var bdate = b['expiry'] //var bdate = b.expiry;
     return -adate.compareTo(bdate);
  });

在排序函数中,我收到了这个错误(通过上述修复已解决):
Unhandled Exception: NoSuchMethodError: Class 
'_InternalLinkedHashMap<String, dynamic>'has no instance getter 'expiry'.

谢谢,我在将日期分配给产品之前已经解析过了,请参见上面的更新。 - Manas
`final format = DateFormat('yyyy-M-d H:m:s:S'); final array = [ '2019-11-24 00:00:00:000', '2019-11-22 00:00:00:000', '2019-11-23 00:00:00:000', '2019-11-25 00:00:00:000', '2019-11-22 00:00:00:000', ];array.map(format.parse).toList() ..sort((a, b) => -a.compareTo(b)) ..forEach(print);` - pskink
谢谢@pskink,看起来错误实际上是由于sort方法尝试获取expiry而引发的此错误:Unhandled Exception: NoSuchMethodError: Class '_InternalLinkedHashMap<String, dynamic>' has no instance getter 'expiry' - Manas
不,我的代码没有任何“过期时间”,首先按照原样运行我的代码(不做任何更改),看看它的工作原理,最后根据需要更改您的代码 - 基本上关键在于DateFormat()构造函数和如何处理sort方法。 - pskink
@pskink,谢谢!我已经让它工作了,对不起,我没有单独运行你的代码,我只是修改了自己的代码。所以实际上是在a.expiry上出了问题,我将其改为a['expiry'],现在它可以正确排序了,我尝试切换adate.compareTo(bdate)-bdate.compareTo(adate)来确认,排序效果非常好!非常感谢。你能把它发布为答案吗,这样我就可以标记它了吗? - Manas
显示剩余4条评论
8个回答

121
在你上面的例子中,expiry是一个String,而不是DateTime对象。你有几个选项,具体取决于你想要实现什么。
最简单的解决方案是使用String内置的compareTo方法,它允许对字符串进行排序。这些时间戳已经处于可排序格式,所以这将起作用:
products.sort((a,b) {
    return a.compareTo(b);
 });

更简洁地说:

products.sort((a,b) => a.compareTo(b));

这很基础。就像pskink在评论中提到的那样,你可以在此基础上将字符串转换为实际的日期时间对象。

DateTime expiryAsDateTime = DateTime.parse(expiry);

DateTime类也有一个内置的compareTo方法,因此上面的代码片段可以用于比较DateTime和字符串。

如果需要颠倒顺序,只需交换ab即可。


谢谢@MichaelM的回答,我已经在将日期分配到产品列表之前解析了它。顺便问一下,这个函数会返回什么顺序?如果我想要相反的顺序,我该如何修改你上面提到的products.sort((a,b) => a.compareTo(b));函数? - Manas
2
compareTo方法按升序排序。如果要交换顺序,只需执行以下操作:products.sort((a,b) => b.compareTo(a));我在我的回答中提供了文档链接。 - MichaelM
太棒了!谢谢 @MichaelM,现在根据日志检查,错误主要在排序函数上,我认为排序函数无法访问列表中的 expiry。请查看我更新的问题的最后一段以获取错误信息。 - Manas
谢谢!我已经使用你第一个建议的方法修复了错误! - Manas

27

我通过将 a.expiry 改为 a['expiry'],并将 b.expiry 改为 b['expiry'] 来进行修复。

products.sort((a,b) {
 var adate = a['expiry'] //before -> var adate = a.expiry;
 var bdate = b['expiry'] //before -> var bdate = b.expiry;
 return adate.compareTo(bdate); //to get the order other way just switch `adate & bdate`
});

19

转换为日期时间类型

import 'package:intl/intl.dart';

void main() {
  List products = [
    "2019-11-25 00:00:00.000",
    "2019-11-22 00:00:00.000",
    "2019-11-22 00:00:00.000",
    "2019-11-24 00:00:00.000",
    "2019-11-23 00:00:00.000"
  ];
  List<DateTime> newProducts = [];
  DateFormat format = DateFormat("yyyy-MM-dd");

  for (int i = 0; i < 5; i++) {
    newProducts.add(format.parse(products[i]));
  }
  newProducts.sort((a,b) => a.compareTo(b));

  for (int i = 0; i < 5; i++) {
    print(newProducts[i]);
  }
}

不转换为DateTime

import 'package:intl/intl.dart';

void main() {
  List products = [
    "2019-11-25 00:00:00.000",
    "2019-11-22 00:00:00.000",
    "2019-11-22 00:00:00.000",
    "2019-11-24 00:00:00.000",
    "2019-11-23 00:00:00.000"
  ];

  products.sort((a,b) => a.compareTo(b));

  for (int i = 0; i < 5; i++) {
    print(products[i]);
  }
}

14
如果你有类似以下这样的东西:
{
"id": 100,
"timestamp": "2021-02-02T15:15:11Z",
"name": "Entry1"
}

那么就这样做:

List<Values> _myList = [];
_myList.sort((a,b)=> a["timestamp"].compareTo(b["timestamp"])); 

或者就像我的代码:

task.sort((a,b) => a.createdAt.compareTo(b.createdAt));

Source


11

如果我们更具体一些,可以尝试像这样。

这对我来说完美地起作用了。


transactionList.sort((a, b) {
  int aDate = DateTime.parse(a.dateTime ?? '').microsecondsSinceEpoch;
  int bDate = DateTime.parse(b.dateTime ?? '').microsecondsSinceEpoch;
  return aDate.compareTo(bDate);
});


5

如果你想按照属性名称对对象进行排序,而不必使用DateTime(假设日期和时间是字符串),可以这样做:

products.sort((a, b)=> a['expiry'].compareTo(b['expiry']));

0

0

这些都不起作用,如果你想按项的创建日期进行排序,那么实际上你想按id进行排序。因此,你可以使用:list.sort((h, c) => c.id.compareTo(h.id));


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