我想对List of(整数列表)进行排序,以便将包含数字3的列表放在列表顶部,使剩余元素的现有顺序保持不变。
final ArrayList<ArrayList<Integer>> arrayLists = Lists.newArrayList(
Lists.newArrayList(1, 2),
Lists.newArrayList(1, 2, 3),
Lists.newArrayList(1, 2),
Lists.newArrayList(1, 3),
Lists.newArrayList(1, 4),
Lists.newArrayList(1, 2, 3)
);
System.out.println(arrayLists);
是
[[1, 2], [1, 2, 3], [1, 2], [1, 3], [1, 4], [1, 2, 3]]
初步尝试使用以下比较器
Comparator<List<Integer>> c = new Comparator<List<Integer>>() {
@Override
public int compare(final List<Integer> o1, final List<Integer> o2) {
System.out.println("Compare " + o1 + "<=>" + o2);
if (o1.contains(3))
return -1;
return 0;
}
};
Collections.sort(arrayLists, c);
System.out.println(arrayLists);
返回
Compare [1, 2, 3]<=>[1, 2]
Compare [1, 2]<=>[1, 2, 3]
Compare [1, 2]<=>[1, 2]
Compare [1, 3]<=>[1, 2]
Compare [1, 3]<=>[1, 2, 3]
Compare [1, 4]<=>[1, 2]
Compare [1, 4]<=>[1, 2]
Compare [1, 2, 3]<=>[1, 2]
Compare [1, 2, 3]<=>[1, 2, 3]
Compare [1, 2, 3]<=>[1, 3]
[[1, 2, 3], [1, 3], [1, 2, 3], [1, 2], [1, 2], [1, 4]]
这是预期的(所有包含3的列表都在顶部)
然而,深入了解javadoc for Comparator表明
实现者必须确保所有x和y的sgn(compare(x,y))== -sgn(compare(y,x))。
实现者还必须确保关系是传递的:((compare(x,y)&gt; 0)&amp;&amp;(compare(y,z)&gt; 0))暗示比较(x,z)&gt ; 0
最后,实现者必须确保compare(x,y)== 0意味着所有z的sgn(compare(x,z))== sgn(compare(y,z))
上述比较器没有完全实现,下面的测试很容易断言。
final ArrayList<Integer> x = Lists.newArrayList(1, 2, 3);
final ArrayList<Integer> y = Lists.newArrayList(1, 2);
System.out.println(c.compare(x,y));
System.out.println(c.compare(y,x));
Compare [1, 2, 3]<=>[1, 2] => -1
Compare [1, 2]<=>[1, 2, 3] => 0 which is not -(-1)
有没有办法真正证明上面的比较器不适用于某些特定的示例List(它没有将包含3的列表放在顶部)?
答案 0 :(得分:3)
有没有办法证明上面的比较器在某些情况下不起作用?
是。最明显的原因是它可以返回-1
但不会返回正数。这显然违反了第一条规则。
不违反规则的比较器是
Comparator<List<Integer>> c = new Comparator<List<Integer>>() {
@Override
public int compare(final List<Integer> o1, final List<Integer> o2) {
return Integer.compare(o1.contains(3) ? 0 : 1, o2.contains(3) ? 0 : 1);
}
};
在Java 8中,您可以将其简化为
Comparator<List<Integer>> c = Comparator.comparingInt(o -> o.contains(3) ? 0 : 1);
我建议使用新方法Comparator.comparingX
。除了减少冗长之外,它还使编写正确的compare
方法变得更加容易。
这是有效的,Collections.sort
的文档保证
这种保证是稳定的:相同的元素不会因排序而重新排序。
另一种方法是迭代原始列表并形成两个单独的列表,一个包含包含3
的列表,另一个包含不包含3
的列表,然后在addAll
处使用sort
结束。这比使用O(n)
(O(n log n)
而不是module Gexcore
class Myability
include CanCan::Ability
def initialize(user)
can :delete_user, User do |victim|
..
end
end
end
end
)的方法具有更好的时间复杂度。
答案 1 :(得分:2)
问题是你没有回复1
。您需要在比较中考虑所有个案。所以你应该拥有的是
Comparator<List<Integer>> c = new Comparator<List<Integer>>() {
@Override
public int compare(final List<Integer> o1, final List<Integer> o2) {
System.out.println("Compare " + o1 + "<=>" + o2);
if (o1.contains(3) && !o2.contains(3)) {
return -1;
} else if (!o1.contains(3) && o2.contains(3)) {
return 1;
} else {
return 0;
}
}
};
<强>更新强>
要证明您的比较在某些情况下不起作用,请x
为包含3的列表,y
为列表不,其中包含3个。您的比较我们将sgn(compare(x, y))
视为否定,将sgn(compare(y, x))
视为零,使Comparator
合约的第一个条件无效。
此外,由于您的比较并未返回正值,因此您无法获得任何传递性。这无视合同的其他两个条件。
通常,您希望尽可能考虑所有情况。这将确保稳定的代码。
答案 2 :(得分:1)
根据文档中提到的限制,有一些改进比较器或使比较器有效的建议。
但实际问题是
有没有办法真正证明上面的比较器不适用于某些特定的示例List(它没有将包含3的列表放在顶部)?
答案是:是的,有。
这可能不是您实际的意图背后的问题。但是一个非常实用的检查可能看起来像这样:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class ComparatorTest
{
public static void main(String[] args)
{
List<List<Integer>> arrayLists = new ArrayList<List<Integer>>(
Arrays.asList(
Arrays.asList(1, 2),
Arrays.asList(1, 2, 3),
Arrays.asList(1, 2),
Arrays.asList(1, 3),
Arrays.asList(1, 4),
Arrays.asList(1, 2, 3)
));
System.out.println(arrayLists);
Comparator<List<Integer>> c = new Comparator<List<Integer>>() {
@Override
public int compare(final List<Integer> o1, final List<Integer> o2) {
//System.out.println("Compare " + o1 + "<=>" + o2);
if (o1.contains(3))
return -1;
return 0;
}
};
Collections.sort(arrayLists, c);
System.out.println(arrayLists);
validate(arrayLists, c);;
}
private static <T> void validate(
List<T> list, Comparator<? super T> comparator)
{
for (int i=0; i<list.size(); i++)
{
for (int j=0; j<list.size(); j++)
{
T x = list.get(i);
T y = list.get(j);
int xy = comparator.compare(x, y);
int yx = comparator.compare(y, x);
if (Math.signum(xy) != -Math.signum(yx))
{
System.out.println(
"The implementor must ensure that " +
"sgn(compare(x, y)) == -sgn(compare(y, x)) " +
"for all x and y.");
System.out.println("This is not the case for x="+x+", y="+y);
}
for (int k=0; k<list.size(); k++)
{
T z = list.get(k);
int yz = comparator.compare(y, z);
int xz = comparator.compare(x, z);
if (xy > 0 && yz > 0)
{
if (xz <= 0)
{
System.out.println(
"The implementor must ensure that " +
"the relation is transitive: " +
"((compare(x, y)>0) && (compare(y, z)>0)) " +
"implies compare(x, z)>0.");
System.out.println(
"This is not the case for " +
"x="+x+", y="+y+", z="+z);
}
}
if (xy == 0)
{
if (Math.signum(xz) != -Math.signum(yz))
{
System.out.println(
"Ihe implementor must ensure that " +
"compare(x, y)==0 implies that " +
"sgn(compare(x, z))==sgn(compare(y, z)) " +
"for all z");
System.out.println(
"This is not the case for " +
"x="+x+", y="+y+", z="+z);
}
}
}
}
}
}
}
该程序的输出是
The implementor must ensure that sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y.
This is not the case for x=[1, 2, 3], y=[1, 2, 3]
The implementor must ensure that sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y.
This is not the case for x=[1, 2, 3], y=[1, 3]
...
Ihe implementor must ensure that compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z
This is not the case for x=[1, 2], y=[1, 2, 3], z=[1, 2, 3]
Ihe implementor must ensure that compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z
This is not the case for x=[1, 2], y=[1, 2, 3], z=[1, 3]
...
列出给定比较器和给定列表的所有合同违规行为。
答案 3 :(得分:0)
如果您想保留订单,请尝试以下初始数据:
final ArrayList<ArrayList<Integer>> arrayLists = Lists.newArrayList(
Lists.newArrayList(3, 1, 2),
Lists.newArrayList(1, 2),
Lists.newArrayList(1, 2, 3),
Lists.newArrayList(1, 2),
Lists.newArrayList(1, 3),
Lists.newArrayList(1, 4),
Lists.newArrayList(1, 2, 3)
);
您可以看到订单未保留,因为最终结果是:
[[1, 2, 3], [1, 3], [1, 2, 3], [3, 1, 2], [1, 2], [1, 4]]
您的比较器始终将包含3值的列表放在最上面,但不能确保保留订单。为此,您必须按照文档中的说明实现对称比较。