"相同排序"的重要性是什么?对象是平等的?

时间:2015-08-27 18:53:58

标签: java sorting comparator

我正在排序一个对象数组。对象有很多字段,但我只关心其中一个。所以,我写了一个比较器:

    Collections.sort(details, new Comparator<MyObj>() {
        @Override
        public int compare(MyObj d1, MyObj d2) {
            if (d1.getDate() == null && d2.getDate() == null) {
                return 0;
            } else if (d1.getDate() == null) {
                return -1;
            } else if (d2.getDate() == null) {
                return 1;
            }

            if (d1.getDate().before(d2.getDate())) return 1;
            else if (d1.getDate().after(d2.getDate())) return -1;
            else return 0;
        }
    });

从我的用例的角度来看,这个Comparator完成了所有需要,即使我可能认为这种排序是非确定性的。但是,我想知道这是不好的代码。通过这个Comparator,可以考虑两个非常不同的对象&#34;相同的&#34;即使它们是不相等的物体也要排序。我决定使用hashCode作为决胜局,它出现了类似的内容:

    Collections.sort(details, new Comparator<MyObj>() {
        @Override
        public int compare(MyObj d1, MyObj d2) {

            if (d1.getDate() == null && d2.getDate() == null) {
                return d1.hashCode();
            } else if (d1.getDate() == null) {
                return -1;
            } else if (d2.getDate() == null) {
                return 1;
            }

            if (d1.getDate().before(d2.getDate())) return 1;
            else if (d1.getDate().after(d2.getDate())) return -1;
            else return d1.hashCode() - d2.hashCode();
        }
    });

(我归来的可能是倒退,但这对这个问题并不重要)

这有必要吗?

修改 对于其他任何查看此问题的人,请考虑使用Google的订购API。上面的逻辑被替换为:

 return Ordering.<Date> natural().reverse().nullsLast().compare(d1.getDate(), d2.getDate());

2 个答案:

答案 0 :(得分:8)

  

通过这个比较器,可以考虑两个非常不同的对象&#34;相同&#34;即使它们是不相等的物体也要排序。

这真的不重要;对于两个对象比较是完全正常的,即使它们不是&#34;相等&#34;在任何其他意义上。 Collections.sort是一个稳定的排序,意味着比较相等的对象按照它们的相同顺序出现;这相当于只使用&#34;输入中的索引&#34;作为决胜局。

(另外,您的新Comparator实际上比原来的return d1.hashCode()要严重得多。return d1.hashCode() - d2.hashCode()特别荒谬,Collections.sort会导致违反Integer.compare的非传递性排序,由于溢出问题。除非两个整数都是非负的,哪个hashCodes不是,否则总是使用ParseQuery<ParseUser> query = ParseUser.getQuery(); query.findInBackground(new FindCallback<ParseUser>(){ public void done(List<ParseUser> userList, ParseException e) { if (e == null) { Log.d("score", "Retrieved " + userList.size() + " scores"); friends = new ArrayList<>();//<-- Initialize the String array for (int i = 0; i < userList.size(); i++) { friends.add(userList.get(i).getUsername()); } aAdapter = new ArrayAdapter<String>(context, android.R.layout.simple_dropdown_item_1line, friends); friendChooser.setAdapter(aAdapter); } else { Log.d("score", "Error: " + e.getMessage()); } } }); 来比较整数。)

答案 1 :(得分:2)

如果对象implement Comparable

,这只是最重要的
  

强烈建议(尽管不要求)自然排序与equals一致。 这是因为没有显式比较器的有序集(和有序映射)表现得很奇怪&#34;奇怪的是#34;当它们与自然排序与equals不一致的元素(或键)一起使用时。特别是,这样的有序集(或有序映射)违反了集合(或映射)的一般契约,它是用术语定义的。等于方法。

     

例如,如果添加两个键a和b使得(!a.equals(b) && a.compareTo(b) == 0)到不使用显式比较器的有序集,则第二个add操作返回false(并且有序集的大小确实如此)不要增加)因为a和b在排序集的视角中是等价的。

但是,您没有这样做,您可能会出于演示原因使用自定义Comparator。由于此排序指标并非固有地附加到对象上,因此它并不重要。

顺便说一句,为什么不返回0而不是乱用hashCodes?然后,如果日期匹配,他们将保留原始订单,因为Collections.sortstable sort。我同意@LouisWasserman以这种方式使用hashCode可能会产生非常奇怪的后果,主要与整数溢出有关。考虑d1.hashCode()为正且d2.hashCode()为负数的情况,反之亦然。