流分类问题

时间:2019-02-12 21:21:12

标签: java sorting java-8 java-stream

我有一个要使用流排序方法排序的项目列表(MyDetail对象)。该对象具有3个字段:field1,field2,field3。 我想先按field3排序,然后按field2再按field1排序,所有顺序都相反。 所以我写了一个方法sortMyList。

我有一个未排序项目unSortedDetails的列表,如下所示:                     myDetail1:“ 20180201”,错误,错误                     myDetail2:“ 20180101”,错误,错误                     myDetail3:“ 20180101”,错误,正确

sortMyList(unSortedDetails)之后,我希望我的结果是myDetail3,myDetail1,myDetail2,但实际结果是myDetail1,myDetail3,myDetail2,为什么?

因此,如果我像以下那样实现MyDetail的Comparable,那么它将按预期工作。这太奇怪了。我不知道为什么。谢谢你的帮助!

public List<MyDetail> sortMyList(List<MyDetail> unSortedDetails){
    List<MyDetail> myDetails = unSortedDetails
                        .stream().sorted(Comparator.comparing(MyDetail::getField11).reversed()
                                .thenComparing(MyDetail::getField2).reversed()
                                .thenComparing(MyDetail::getField3).reversed())
                        .collect(Collectors.toList());
                        return myDetails;
                        }

                        @Setter
                        @Getter
                        public class MyDetail{
                            String field1;
                            Boolean field2; 
                            Boolean field3; 
                        }



                @Setter
                @Getter
                public class MyDetail implement Comparable<MyDetail>{
                    String field1;
                    Boolean field2; 
                    Boolean field3; 

                        @Override
                        public int compareTo(MyDetail o) {
                            if (this == o || this.equals(o)) return 0;
                            if (field3) return -1;
                            if (o.field3) return 1;
                            if (!field3 && !o.field3 && field2) return -1;
                            if(!field3 && !o.field3 &&!field2 && o.field2) return 1;
                            if(!field3 && !o.field3
                                    &&!field2 && !o.field2){
                                return o.field1.compareTo(field1);
                            }
                            return 0;
}
                }

1 个答案:

答案 0 :(得分:6)

比较器几乎没有问题。首先,每次调用reversed()时,您都将反转比较器的 all 先前的所有设置。

所以您的比较器代表了(请参见注释中的步骤,FieldX简化为Fx

Comparator.comparing(MyDetail::getField11)     //  F1 ASC
          .reversed()                          //~(F1 ASC) 
                                               //  F1 DESC 
          .thenComparing(MyDetail::getField2)  //  F1 DESC, F2 ASC  
          .reversed()                          //~(F1 DESC, F2 ASC) 
                                               //  F1 ASC,  F2 DESC
          .thenComparing(MyDetail::getField3)  //  F1 ASC,  F2 DESC, F3 ASC
          .reversed()                          //~(F1 ASC,  F2 DESC, F3 ASC)
                                               //  F1 DESC, F2 ASC,  F3 DESC

所以您最终得到订单Field1 DESC, Field2 ASC, Field3 DESC

要为每个字段指定颠倒顺序,请通过 传递该字段已经颠倒的比较器 ,例如.thenComparing(Comparator.comparing(YourClass::getField).reversed())


下一个问题是比较器使用的字段顺序。在您的问题中,您说:

  

我想先按field3排序,然后按field2排序,然后按field1排序

但是您的比较器首先检查field1,然后检查field2,然后检查field3(因为您是通过.thenComparing依次添加的)。

您的代码应该更像

Comparator.comparing(MyDetail::getField13).reversed()
          .thenComparing(Comparator.comparing(MyDetail::getField2).reversed())
          .thenComparing(Comparator.comparing(MyDetail::getField1).reversed())

因此,您正在创建~(F3 ASC), ~(F2 ASC), ~(F1 ASC),结果为F3 DESC, F2 DESC, F1 DESC


顺便说一句,pointedHolger一样,您可以通过

达到相同的效果
Comparator.comparing(MyDetail::getField3)
          .thenComparing(MyDetail::getField2) 
          .thenComparing(MyDetail::getField1)
          .reversed()

请注意,Comparaor.comparing(FunctionToValue)thenComparing(FunctionToValue)将为选定的值创建升序比较器。

因此,前3行构造了比较器,描述了顺序F3 ASC, F2 ASC, F1 ASC。反转后
~(F3 ASC, F2 ASC, F1 ASC)也给了我们想要的F3 DESC, F2 DESC, F1 DESC