我有一个名为 outputToStore 的嵌套列表,其内容如下:[[Final, 331, M, 22/03/2020 00:00:00], [Initial, 335, M, 22/06/2022 00:00:00], [Exception, 335, M, 22/05/2022 00:00:00]...
我有一个 嵌套列表 , outputToStore
其内容如下:
[[Final, 331, M, 22/03/2020 00:00:00],
[Initial, 335, M, 22/06/2022 00:00:00],
[Exception, 335, M, 22/05/2022 00:00:00],
[Final, 335, M, 20/06/2022 00:00:00],
[Keep, 335, M, 02/06/2022 11:00:00],
[Final, 335, M, 10/04/2022 02:00:00],
[Deleted, 335, M, 22/06/2022 15:55:10],
[Exception, 335, M, 22/06/2022 15:55:09],
[Final, 335, M, 22/06/2022 15:56:00],
[Initial, 335, M, 11/06/2022 00:00:00]]
我需要根据两个条件进行排序:第一个是自定义顺序: \'Initial\',\'Final\',\'Deleted\',\'Keep\',\'Exception\' ,然后基于 日期时间 .
我能做到,但不确定这是否是最好的方法。
我的代码:
List<String> definedOrder = Arrays.asList("Initial","Final","Deleted","Keep","Exception");
Collections.sort(outputToStore, Comparator.comparing(o -> Integer.valueOf(definedOrder.indexOf(o.get(0)))));
Collections.sort(outputToStore,( o1, o2)-> {
// let your comparator look up your car's color in the custom order
try {
if(Integer.valueOf(definedOrder.indexOf(o1.get(0))).compareTo(Integer.valueOf(definedOrder.indexOf(o2.get(0))))==0){
Date date1=simpleDateFormat.parse(o1.get(3));
Date date2=simpleDateFormat.parse(o2.get(3));
return date1.compareTo(date2);
}
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
});
我得到了期望的结果:
[[Initial, 335, M, 11/06/2022 00:00:00],
[Initial, 335, M, 22/06/2022 00:00:00],
[Final, 331, M, 22/03/2020 00:00:00],
[Final, 335, M, 10/04/2022 02:00:00],
[Final, 335, M, 20/06/2022 00:00:00],
[Final, 335, M, 22/06/2022 15:56:00],
[Deleted, 335, M, 22/06/2022 15:55:10],
[Keep, 335, M, 02/06/2022 11:00:00],
[Exception, 335, M, 22/05/2022 00:00:00],
[Exception, 335, M, 22/06/2022 15:55:09]]
但是有没有更好或者更简洁的方法来做到这一点?
您表示数据的方式不方便并且容易出错。
它显然必须是一个 对象 ,而不是字符串列表。这是对集合的滥用
用作 String
数字、日期等的类型不会给您带来任何好处。除了在控制台上打印之外,您无法对字符串进行任何解析。正确的数据类型可让您访问其 String
无法提供的独特行为。
第一个属性,我们称之为 status
枚举 是—— . Enum 一种特殊的类,当您需要表示一组有限的值时,它们非常方便,并且它们具有 自然顺序 枚举常量 (它们被声明的顺序) 相同
为了表示日期时间信息,我们可以使用包中的 Java 8 类之一 java.time
。在下面的示例中,我将使用 LocalDateTime
(类 Date
是遗留的,请避免使用它)。
这样的课程可能看起来像这样:
public class Foo {
public enum Status {INITIAL, FINAL, DELETED, KEEP, EXCEPTION}
private CountComponents.Foo.Status status;
private int value1;
private String value2;
private LocalDateTime dateTime;
// constructor, getters, etc.
}
为了对 Foo
对象列表进行排序,我们需要定义一个比较器。
为此,我们可以使用 Comparator
Java 8 接口中引入的静态方法。我们可以流畅地链接这些方法,因为它们每个方法都提供了一个比较器。
Comparator<Foo> byStatusByDate =
Comparator.comparing(Foo::getStatus)
.thenComparing(Foo::getDateTime);
注意: 单个比较器 中定义排序逻辑 。不要像在代码中那样对数据进行两次排序,这会造成不必要的性能开销。
要了解如何使用 Java-8 方法构建比较器,请查看 本教程 .
为了对对象列表进行排序 Foo
,我们可以使用 List.sort()
Java 9 中引入的方法,作为更流畅的替代 Collections.sort()
:
List<Foo> foos = // initializing the list
foos.sort(byStatusByDate);
如果数据以字符串集合的形式出现在您面前,那么您需要对其进行解析。
为此,我们需要增强 Foo
及其嵌套 枚举 (完整的代码在下面的链接中提供)。
public static class Foo {
public enum Status {
INITIAL, FINAL, DELETED, KEEP, EXCEPTION;
public static Status parse(String str) {
return Arrays.stream(values())
.filter(cons -> cons.name().equalsIgnoreCase(str))
.findFirst()
.orElseThrow();
}
}
private Status status;
private int value1;
private String value2;
private LocalDateTime dateTime;
public static Foo parse(List<String> strings, DateTimeFormatter formatter) {
return new Foo(Status.parse(strings.get(0)),
Integer.parseInt(strings.get(1)),
strings.get(2),
LocalDateTime.parse(strings.get(3), formatter));
}
// constructor, getters, etc.
}
注意: SimpleDateFormat
类是遗留的,现代替代品是 DateTimeFormatter
.
main()
public static void main(String[] args) {
List<List<String>> strings = List.of(
List.of("Final", "331", "M", "22/03/2020 00:00:00"),
List.of("Initial", "335", "M", "22/06/2022 00:00:00"),
List.of("Exception", "335", "M", "22/05/2022 00:00:00"),
List.of("Final", "335", "M", "20/06/2022 00:00:00"),
List.of("Keep", "335", "M", "02/06/2022 11:00:00"),
List.of("Final", "335", "M", "10/04/2022 02:00:00"),
List.of("Deleted", "335", "M", "22/06/2022 15:55:10"),
List.of("Exception", "335", "M", "22/06/2022 15:55:09"),
List.of("Final", "335", "M", "22/06/2022 15:56:00"),
List.of("Initial", "335", "M", "11/06/2022 00:00:00")
);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
Comparator<Foo> byStatusByDate =
Comparator.comparing(Foo::getStatus)
.thenComparing(Foo::getDateTime);
List<Foo> foos = strings.stream() // Stream<List<String>>
.map(list -> Foo.parse(list,formatter)) // Stream<Foo>
.sorted(byStatusByDate)
.collect(Collectors.toList()); // or .toList() for Java 16 +
foos.forEach(System.out::println); // printing the result
}
输出:
Foo{status=INITIAL, value1=335, value2='M', dateTime=2022-06-11T00:00}
Foo{status=INITIAL, value1=335, value2='M', dateTime=2022-06-22T00:00}
Foo{status=FINAL, value1=331, value2='M', dateTime=2020-03-22T00:00}
Foo{status=FINAL, value1=335, value2='M', dateTime=2022-04-10T02:00}
Foo{status=FINAL, value1=335, value2='M', dateTime=2022-06-20T00:00}
Foo{status=FINAL, value1=335, value2='M', dateTime=2022-06-22T15:56}
Foo{status=DELETED, value1=335, value2='M', dateTime=2022-06-22T15:55:10}
Foo{status=KEEP, value1=335, value2='M', dateTime=2022-06-02T11:00}
Foo{status=EXCEPTION, value1=335, value2='M', dateTime=2022-05-22T00:00}
Foo{status=EXCEPTION, value1=335, value2='M', dateTime=2022-06-22T15:55:09}
在线演示链接
尝试一下。
static final List<String> definedOrder = List.of(
"Initial","Final","Deleted","Keep","Exception");
static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
record Rec(int key0, Date key1, List<String> row) {}
static Date parseDate(String input) {
try {
return simpleDateFormat.parse(input);
} catch (ParseException e) { throw new RuntimeException(e); }
}
public static void main(String[] args) {
List<List<String>> outputToStore = Arrays.asList(
Arrays.asList("Final", "331", "M", "22/03/2020 00:00:00"),
Arrays.asList("Initial", "335", "M", "22/06/2022 00:00:00"),
Arrays.asList("Exception", "335", "M", "22/05/2022 00:00:00"),
Arrays.asList("Final", "335", "M", "20/06/2022 00:00:00"),
Arrays.asList("Keep", "335", "M", "02/06/2022 11:00:00"),
Arrays.asList("Final", "335", "M", "10/04/2022 02:00:00"),
Arrays.asList("Deleted", "335", "M", "22/06/2022 15:55:10"),
Arrays.asList("Exception", "335", "M", "22/06/2022 15:55:09"),
Arrays.asList("Final", "335", "M", "22/06/2022 15:56:00"),
Arrays.asList("Initial", "335", "M", "11/06/2022 00:00:00")
);
List<List<String>> sorted = outputToStore.stream()
.map(e -> new Rec(definedOrder.indexOf(e.get(0)), parseDate(e.get(3)), e))
.sorted(Comparator.comparingInt(Rec::key0).thenComparing(Rec::key1))
.map(Rec::row)
.toList();
for (List<String> row : sorted)
System.out.println(row);
}
输出:
[Initial, 335, M, 11/06/2022 00:00:00]
[Initial, 335, M, 22/06/2022 00:00:00]
[Final, 335, M, 10/04/2022 02:00:00]
[Final, 335, M, 20/06/2022 00:00:00]
[Final, 331, M, 22/03/2020 00:00:00]
[Final, 335, M, 22/06/2022 15:56:00]
[Deleted, 335, M, 22/06/2022 15:55:10]
[Keep, 335, M, 02/06/2022 11:00:00]
[Exception, 335, M, 22/05/2022 00:00:00]
[Exception, 335, M, 22/06/2022 15:55:09]
由于 Java 8 Date 和 SimpleDateFormat 被视为遗留,不鼓励使用。应改用 java.time 包中的类。
对于预定义的顺序和按日期进行比较,使用映射可能更好 LocalDateTime
。但除此之外,你的思路是对的;你可以直接链接 thenComparing
到你的 Comparator :
Map<String,Integer> definedOrder = Map.of(
"Initial", 1, "Final", 2, "Deleted", 3, "Keep", 4, "Exception", 5);
final DateTimeFormatter df = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
outputToStore.sort(Comparator.comparing((List<String> list) -> definedOrder.get(list.get(0)))
.thenComparing(Comparator.comparing(list -> LocalDateTime.parse(list.get(3), df)))
);