更新:事实上,此问题唯一可接受的解决方案是将数组升序排序,然后将其反转。
让 S 成为以下事件序列:
Event | Time
A | 0:00
B | 0:01
C | 0:01
D | 0:02
我有一个简单的比较器来排序 S ,它根据 time 值对元素进行排序。
public int compare(Event e1, Event e2) {
// Reverse sorting.
// _sortOrder is set outside this method.
if(SORT_DESCENDING.equals(_sortOrder))
return e2.getTime() - e1.getTime(); /* time is long */
return e1.getTime() - e2.getTime();
}
问题是:当排序顺序升序时, S 正确排序:A,B,C,D。
但是当我使用反向排序时, S 变为D,B,C,A:
Event | Time
D | 0:02
B | 0:01 /* B and C should be reversed */
C | 0:01
A | 0:00
这是因为默认排序算法保留了具有相同 time 值的元素的原始顺序。
那么,如何在不保留原始订单的情况下对其进行排序?
注意:我知道我可以将 S 升序排序并进一步简单地还原它,但不幸的是,这不是我的选择。
答案 0 :(得分:3)
你在用什么来排序?我猜这是保证它是stable sort的东西 - 就比较而言,你有两个相等的值。
在这种情况下,您可以施加任何额外的顺序吗?你能否轻松地告诉哪一个事件会在升序中排在第一位?如果是这样,只需使用原始比较,然后降序将开始自然地工作。
编辑:由于您的数据中没有任何额外的订购信息,如果在Oracle中再次执行相同的查询时以不同的顺序返回,我不会感到惊讶。但是,如果你只关心这个特定情况下的顺序,我建议你在Java内存表示中添加一个额外的字段来将原始索引存储在加载的列表中 - 当你读取数据时,记录多少你已经阅读并相应地分配了字段。然后你可以在排序时使用它。
答案 1 :(得分:3)
排序算法正确:0.01为0.01。除非你有什么东西没告诉我们。但是,如果您想要升序排序的完全相反顺序,则按升序排序并使用Collections.reverse()。我的意思是:
List<SomeObject> list = ...;
Collections.sort(list, myComparator);
Collections.reverse(list);
将为您提供您想要的内容。
但如果倒车不是一种选择,你只剩下两个选择:
现在在你说你无法扭转之前(为什么?),让我问你如何排序?如果你正在使用Collections.sort()
考虑源代码(Java 6u10):
public static <T extends Comparable<? super T>> void sort(List<T> list) {
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator<T> i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
因此,它将集合复制到一个数组中,对该数组进行排序,然后使用它来重新排序集合。
你确定无法承受逆转吗?
答案 2 :(得分:1)
我认为你真正想要的是二级排序标准,这样即使主排序标准认为项目相等,你也可以对项目进行排序。在您的示例中,主要标准是时间,辅助标准是“事件”。这样,在执行排序之前,您不必依赖于特定顺序的项目,这使事情变得更加容易。
如果你真的没有辅助标准,你可能需要研究稳定与不稳定的排序算法,如Jon Skeet所说。
答案 3 :(得分:1)
我错过了什么,或者你不能只使用事件名称(或A,B,C和D)作为辅助排序键吗?只需将您的比较器扩展为:
public int compare(Event e1, Event e2) {
int cmp = e1.getTime() - e2.getTime(); // compare times
if (cmp == 0) // if times are equal, compare names instead
cmp = e1.getName().compareTo(e2.getName());
return SORT_DESCENDING.equals(_sortOrder)? -cmp : cmp;
}
答案 4 :(得分:1)
另一种方法但不解决您的问题:
List<SomeObject> list = ...;
Collections.sort(list, Collections.<SomeObject>reverseOrder());
答案 5 :(得分:0)
为什么0:01小于/大于0:01,或者为什么如果两者都相同,就应该以非常特殊的方式进行排序?
你不是在寻找反向排序,你正在寻找一种反向排序,对不起。 :)
答案 6 :(得分:0)
排序顺序看起来是正确的,只需比较e1.getTime()== e2.getTime()的名称。
答案 7 :(得分:0)
根据比较两个元素与切换它们的速度有多快,您可以只进行降序稳定排序,然后仅反转“相等”元素的所有区域。