【问题标题】:Sort the Objects with comparator logic in java在java中使用比较器逻辑对对象进行排序
【发布时间】:2018-03-20 02:01:04
【问题描述】:

我正在尝试使用以下参数对对象列表进行排序

a.将partId与其他对象id相同的两个list对象分组

b.将 partId 为 null 的任何对象推送到列表末尾。

c。根据计数升序对分组的对象进行排序,首选是

我。组中的两个对象的计数都应该更少

二。那么组中的任何对象的计数都比其他组少。

下面是我目前的代码,

public class ListTTest {
    public static void main(String[] args) {
        LstObj lstObj1 = new LstObj("0:0:1", "1:0:1", 49);
        LstObj lstObj2 = new LstObj("0:0:2", "1:0:2", 2);
        LstObj lstObj3 = new LstObj("0:2:1", "1:2:1", 0);
        LstObj lstObj4 = new LstObj("0:2:2", null , 0);
        LstObj lstObj5 = new LstObj("0:2:3", "1:2:3" , 2);
        LstObj lstObj6 = new LstObj("0:2:4", "1:2:4" , 49);
        LstObj lstObj7 = new LstObj("1:0:1", "0:0:1" , 49);
        LstObj lstObj8 = new LstObj("1:0:2", "0:0:2" , 49);
        LstObj lstObj9 = new LstObj("1:2:1", "0:2:1" , 0);
        LstObj lstObj10 = new LstObj("1:2:2", null , 0);
        LstObj lstObj11 = new LstObj("1:2:3", "0:2:3" , 49);
        LstObj lstObj12 = new LstObj("1:2:4", "0:2:4" , 49);


        LstObj lst[] = new LstObj[]{lstObj1,lstObj2,lstObj3,lstObj4,lstObj5,lstObj6,lstObj7,lstObj8,lstObj9,lstObj10,lstObj11,lstObj12};
        List<LstObj> lstArr = Arrays.asList(lst);

        lstArr.sort(new Comparator<LstObj>() {
            @Override
            public int compare(LstObj o1, LstObj o2) {
                    if(o1.partId==null){
                        return 1;
                    }else if(o2.partId==null){
                         return -1;
                    }else{
                        return -1*(o1.partId.compareTo(o2.id)-(o1.count-o2.count));
                    }

            }
        });

        System.out.println(lstArr);
    }


}

class LstObj {
    String partId;
    String id;
    int count;

    public LstObj(  String id,
    String partId,
    int count
    ) {
        this.count = count;
        this.partId = partId;
        this.id = id;       
    }

    public String getPartId() {
        return partId;
    }
    public String getId() {
        return id;
    }
    public int getCount() {
        return count;
    }
    public void setPartId(String partId) {
        this.partId = partId;
    }
    public void setId(String id) {
        this.id = id;
    }
    public void setCount(int count) {
        this.count = count;
    }

    @Override
    public String toString() {
        return "LstObj [partId=" + partId + ", id=" + id + ", count=" + count
                + "]\n";
    }


}

以上代码的输出是:

[LstObj [partId=1:2:1, id=0:2:1, count=0]
    , LstObj [partId=1:2:3, id=0:2:3, count=2]
    , LstObj [partId=0:2:1, id=1:2:1, count=0]
    , LstObj [partId=1:0:2, id=0:0:2, count=2]
    , LstObj [partId=1:2:4, id=0:2:4, count=49]
    , LstObj [partId=0:2:3, id=1:2:3, count=49]
    , LstObj [partId=1:0:1, id=0:0:1, count=49]
    , LstObj [partId=0:0:1, id=1:0:1, count=49]
    , LstObj [partId=0:0:2, id=1:0:2, count=49]
    , LstObj [partId=0:2:4, id=1:2:4, count=49]
    , LstObj [partId=null, id=0:2:2, count=0]
    , LstObj [partId=null, id=1:2:2, count=0]

但我正在寻找输出为:

 [LstObj [partId=0:2:1, id=1:2:1, count=0]
    , LstObj [partId=1:2:1, id=0:2:1, count=0]
    , LstObj [partId=0:0:2, id=1:0:2, count=2]
    , LstObj [partId=1:0:2, id=0:0:2, count=49]
    , LstObj [partId=0:2:3, id=1:2:3, count=2]
    , LstObj [partId=1:2:3, id=0:2:3, count=49]
    , LstObj [partId=0:0:1, id=1:0:1, count=49]
    , LstObj [partId=1:0:1, id=0:0:1, count=49]
    , LstObj [partId=0:2:4, id=1:2:4, count=49]
    , LstObj [partId=1:2:4, id=0:2:4, count=49]
    , LstObj [partId=null, id=0:2:2, count=0]
    , LstObj [partId=null, id=1:2:2, count=0]

有人知道我到底哪里做错了吗?

【问题讨论】:

  • 不确定错误在哪里,但你应该看看在 Java 8 中添加到 Comparator interface 的方法,例如comparing()thenComparing()nullsLast()。我相信他们可以大大简化您的代码。
  • 比较器应该是对称的。像o1.partId.compareTo(o2.id) 这样的术语不可能是正确的。此外,通过减号将两个比较结果与o1.partId.compareTo(o2.id)-(o1.count-o2.count) 相结合是没有意义的,因为compareTo 返回的值的大小是完全未指定的(无论如何假定的结果是什么)。此外,-1*(…) 是一种翻转符号的冗长方式(-(…) 也可以),这是一种反转比较器的破坏方式。如果比较器的计算结果为Integer.MIN_VALUE,则翻转符号会导致溢出,再次导致Integer.MIN_VALUE……

标签: java java-8


【解决方案1】:

仅通过查看列表的两个元素来实现应用您预期的分组逻辑的比较器是不可能的。

您可以执行专门的分组操作并对组进行排序,然后创建结果列表。内置分组收集器需要一个能够将每个元素分配给一个组而不看到对应组的函数,但是如果您使用稳定的选择器,例如使用partIdid 中的最小值,只要您的输入数据具有正确的形状,正确的元素将最终归为一组。

List<LstObj> lstArr = Arrays.asList(
    new LstObj("0:0:1", "1:0:1", 49),
    new LstObj("0:0:2", "1:0:2", 2),
    new LstObj("0:2:1", "1:2:1", 0),
    new LstObj("0:2:2", null , 0),
    new LstObj("0:2:3", "1:2:3" , 2),
    new LstObj("0:2:4", "1:2:4" , 49),
    new LstObj("1:0:1", "0:0:1" , 49),
    new LstObj("1:0:2", "0:0:2" , 49),
    new LstObj("1:2:1", "0:2:1" , 0),
    new LstObj("1:2:2", null , 0),
    new LstObj("1:2:3", "0:2:3" , 49),
    new LstObj("1:2:4", "0:2:4" , 49)
);

Function<LstObj,Object> groupFunc = o -> {
    String id = o.getId(), partId = o.getPartId();
    return partId == null? Void.TYPE: partId.compareTo(id)<0? partId: id;
};
List<LstObj> result = lstArr.stream()
        .sorted(Comparator.comparing(LstObj::getPartId, Comparator.nullsLast(null))
                          .thenComparingInt(LstObj::getCount))
        .collect(Collectors.groupingBy(groupFunc, LinkedHashMap::new, Collectors.toList()))
        .values().stream()
        .flatMap(List::stream)
        .collect(Collectors.toList());
System.out.println(result);

这会对所有元素进行排序,将所有partIdnull 的对象移动到列表的末尾,并按次要顺序排序。随后的分组操作使用LinkedHashMap,它保留了遇到顺序,有效地根据第一个遇到的元素对组进行排序,这是计数最少的元素。然后将这些组展平为结果列表。

结果满足您问题的指定标准,但未完全生成您发布的所需结果列表,因为组内元素的顺序未指定。上面的代码按计数对它们进行排序,作为初始排序的副作用,并为具有相同计数的元素保持原始列表顺序。

【讨论】:

  • 详尽解释@Holger,感谢学习指点。
  • 上面的代码几乎可以正常工作,但是我们如何根据组中的计数总和对组进行重新排序? [0,0][1,7][1,6] 作为计数应重新排序为 [0,0][1,6][1,7]。你有什么想法吗?
  • 然后,您需要在排序后对组进行排序,例如将上述解决方案的尾部更改为… .values().stream() .sorted(Comparator.comparing(l -&gt; l.stream().mapToInt(LstObj::getCount).sum())) .flatMap(List::stream) .collect(Collectors.toList())。但是,这不会尊重“null partIds to end”约束。当达到这种复杂性时,删除这些特殊对象并在之后重新添加它们将是更简单的选择。
  • 是的,那会更简单。谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-20
  • 1970-01-01
相关资源
最近更新 更多