8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

按两个元素对嵌套列表进行排序

Jonathan Hansen 1月前

39 0

我有一个名为 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]]

但是有没有更好或者更简洁的方法来做到这一点?

帖子版权声明 1、本帖标题:按两个元素对嵌套列表进行排序
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Jonathan Hansen在本站《sorting》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 利用物体的力量

    您表示数据的方式不方便并且容易出错。

    它显然必须是一个 对象 ,而不是字符串列表。这是对集合的滥用

    用作 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.
    }
    

    使用 Java 8 构建比较器

    为了对 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)))
    );
    
返回
作者最近主题: