提问人:sandhu 提问时间:7/8/2022 最后编辑:Alexander Ivanchenkosandhu 更新时间:7/10/2022 访问量:195
对两个元素的嵌套列表进行排序
Sort a nested List on two elements
问:
我有一个嵌套列表,其内容如下: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]]
我需要根据 2 个条件对此进行排序:第一个是自定义顺序:“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
为了表示日期时间信息,我们可以使用包中的 Java 8 类之一。在下面的示例中,我将使用 (class is legacy, avoid use it)。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.
}
使用 Java 8 构建比较器
为了对对象列表进行排序,我们需要定义一个比较器。Foo
为此,我们可以使用在 Java 8 接口中引入的静态方法。我们可以以流畅的方式链接这些方法,因为它们中的每一个都提供了一个比较器。Comparator
Comparator<Foo> byStatusByDate =
Comparator.comparing(Foo::getStatus)
.thenComparing(Foo::getDateTime);
注意:我们需要在单个比较器中定义排序逻辑。不要像在代码中那样对数据进行两次排序,这会导致不必要的性能开销。
要了解如何使用 Java-8 方法构建比较器,请查看本教程。
为了对对象列表进行排序,我们可以使用 Java 9 中引入的方法作为更流畅的替代方案:Foo
List.sort()
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.
}
注意:类是旧版,现代替代项是 DateTimeFormatter
。SimpleDateFormat
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]
评论
Date
SimpleDateFormat
java.time
地图可能更适合用于预定义的顺序,并用于按日期进行比较。但除此之外,你走在正确的轨道上;你可以链接到你的比较器:LocalDateTime
thenComparing
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)))
);
下一个:如何对字符串的嵌套列表进行排序
评论