简体   繁体   English

排序地图 <String, Object> 首先在Object.property1上,然后为每个Object.property1,按Object.property2排序

[英]Sort a Map<String, Object> first on Object.property1 and then for each Object.property1, sort by Object.property2

I have used the below method to Sort a Map first on Object.property1 and then for each Object.property1, sort by Object.property2. 我使用下面的方法首先在Object.property1上对Map进行排序,然后对每个Object.property1进行排序,按Object.property2排序。

for example, 例如,

property1 = TaxIdNumber and property1 = TaxIdNumber和
property2 = ProviderName property2 = ProviderName

I was just wondering this can be done in a more shorter and precise manner. 我只是想知道这可以用更短更精确的方式完成。 Any help or suggestion would be appreciated. 任何帮助或建议将不胜感激。

    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;
    }

You only need one comparator. 你只需要一个比较器。 first compare the taxids. 首先比较出租车。 If they are unequal return -1 or 1 as appropriate. 如果它们是不等的,则返回-1或1。 If they are equals, then compare the provider name. 如果它们是等于,则比较提供者名称。

something like: 就像是:

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);
        }
    });

Your null-handling violates the contract of compare , as you deem null equal to any other value, while the JavaDoc writes: 您的null处理违反了compare的约定,因为您认为null等于任何其他值,而JavaDoc写道:

Compares its two arguments for order. 比较它的两个参数的顺序。 Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. 返回负整数,零或正整数,因为第一个参数小于,等于或大于第二个参数。

and in particular: 特别是:

Finally, the implementor must ensure that compare(x, y)==0 implies that sgn(compare(x, z)) == sgn(compare(y, z)) for all z. 最后,实现者必须确保compare(x, y)==0意味着所有z的sgn(compare(x, z)) == sgn(compare(y, z))

which your code fails to accomplish for x = null , y = "a" , z = "b" . 您的代码无法完成x = nully = "a"z = "b"

Therefore, if any objects or properties in the list are null , the list may not be sorted correctly. 因此,如果列表中的任何对象或属性为null ,则列表可能无法正确排序。

That being said, I wonder if the list may really contain null values or properties? 话虽如此,我想知道列表是否真的包含null值或属性? If not, I'd remove all null checks and end up with 如果没有,我将删除所有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());
    }
}

If the list may contain null objects or properties, you must define whether the null values come first or last, and extend the comparator accordingly: 如果列表可能包含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);
        }
    }
}

Now this is quite a bit of repetitive and tricky code, which is why the folks over at Apache wrote the CompareToBuilder . 现在这是一个相当多的重复和棘手的代码,这就是为什么Apache的人写了CompareToBuilder With that API, you can simply write: 使用该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();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM