首先在Object.property1上对Map <string,object =“”>进行排序,然后对每个Object.property1进行排序,按Object.property2排序</string,>

时间:2011-04-07 12:43:10

标签: java sorting collections

我使用下面的方法首先在Object.property1上对Map进行排序,然后对每个Object.property1进行排序,按Object.property2排序。

例如,

property1 = TaxIdNumber和
   property2 = ProviderName

我只是想知道这可以用更短更精确的方式完成。任何帮助或建议将不胜感激。

    private List<TestObject> sortByValue(final Map m) {
        List<TestObject> values = new ArrayList<TestObject>();
        values.addAll(m.values());

        // First sort the list by Tax ID.
        Collections.sort(values, new Comparator<TestObject>() {
            public int compare(TestObject r1, TestObject r2) {
                Long taxId1 = (r1 == null ? null : r1.getTaxIdNumber());
                Long taxId2 = (r2 == null ? null : r2.getTaxIdNumber());

                if (taxId1 == null || taxId2 == null) {
                    return 0;
                }

                return taxId1.compareTo(taxId2);
            }
        });

        // Then sort the list by Provider name.
        Collections.sort(values, new Comparator<TestObject>() {
            public int compare(TestObject r1, TestObject r2) {
                String name1 = (r1 == null ? null : r1.getProviderName());
                String name2 = (r2 == null ? null : r2.getProviderName());

                if (name1 == null || name2 == null) {
                    return 0;
                }

                if (r1.getTaxIdNumber() == r2.getTaxIdNumber()) {
                    return name1.compareTo(name2);
                } else {
                    return 0;
                }
            }
        });

        return values;
    }

2 个答案:

答案 0 :(得分:2)

你只需要一个比较器。首先比较出租车。如果它们是不等的,则返回-1或1。如果它们相等,则比较提供者名称。

类似的东西:

Collections.sort(values, new Comparator<TestObject>() {
        public int compare(TestObject r1, TestObject r2) {
            Long taxId1 = (r1 == null ? null : r1.getTaxIdNumber());
            Long taxId2 = (r2 == null ? null : r2.getTaxIdNumber());

            if (taxId1 == null || taxId2 == null) {
                return 0;
            }

            int cmp = taxId1.compareTo(taxId2);

            if (cmp != 0)
                return cmp;

            String name1 = (r1 == null ? null : r1.getProviderName());
            String name2 = (r2 == null ? null : r2.getProviderName());

            if (name1 == null || name2 == null) {
                return 0;
            }

            return name1.compareTo(name2);
        }
    });

答案 1 :(得分:2)

您的空值处理违反了compare的约定,因为您认为null等于任何其他值,而JavaDoc写道:

  

比较其订单的两个参数。当第一个参数小于,等于或大于第二个参数时,返回负整数,零或正整数。

,特别是:

  

最后,实施者必须确保compare(x, y)==0暗示所有z都sgn(compare(x, z)) == sgn(compare(y, z))

您的代码无法为x = nully = "a"z = "b"完成。

因此,如果列表中的任何对象或属性为null,则列表可能无法正确排序。

话虽如此,我想知道列表是否真的包含null值或属性?如果没有,我将删除所有null项检查,最后以

结束
Collections.sort(list, new Comparator<TestObject>() {
    @Override public int compare(TestObject o1, TestObject o2) {
        int c = o1.getTaxIdNumber().compareTo(o2.getTaxIdNumber);
        if (c != 0) {
            return c;
        }
        return o1.getProviderName().compareTo(o2.getProviderName());
    }
}

如果列表可能包含null个对象或属性,则必须定义null值是先到还是最后,并相应地扩展比较器:

Collections.sort(list, new Comparator<TestObject>() {
    @Override public int compare(TestObject o1, TestObject o2) {
        // insert null-checks for o1, o2 here

        int c = cmp(getTaxIdNumber(), o2.getTaxIdNumber());
        if (c != 0) {
            return c;
        }
        return cmp(o1.getProviderName(), o2.getProviderName());
    }

    private <T extends Comparable<? super T>> cmp(T o1, T o2) {
        if (o1 == o2) {
            return 0;
        else if (o1 == null) {
            return -1;
        } else if (o2 == null) {
            return 1;
        } else {
            return o1.compareTo(o2);
        }
    }
}

现在这是一个相当多的重复和棘手的代码,这就是为什么Apache的人写了CompareToBuilder。使用该API,您只需编写:

@Override int compare(TestObject r1, TestObject r2) {
    // insert null checks for r1 and r2 here - if you really need them

    return new CompareToBuilder()
        .append(r1.getTaxIdNumber(), r2.getTaxIdNumber())
        .append(r1.getProviderName(), r2.getProviderName())
        .toComparison();
    }
}