Rot*_*cky 5 java reverse method-chaining comparator java-8
假设我想以相反的顺序ArrayList对字段height中的对象进行排序,如果两个值相同,我想以相反的顺序进一步对字段宽度进行排序。有没有办法使用类似的东西
Comparator<Test> comparator = Comparator
.comparingInt((Test t) -> t.height).reversed()
.thenComparingInt((Test t ) -> t.width).reversed();
Run Code Online (Sandbox Code Playgroud)
我知道我可以使用类似的东西:
Collections.sort(list, new Comparator<Test>() {
public int compare(Test o1, Test o2) {
Integer x1 = o1.height;
Integer x2 = o2.height;
int sComp = x2.compareTo(x1);
if (sComp != 0) {
return sComp;
}
x1 = o1.width;
x2 = o2.width;
return x2.compareTo(x1);
}});
Run Code Online (Sandbox Code Playgroud)
但我真的很好奇是否有一行解决方案
所以关于这个小例子
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class Main {
public static void main(String[] args) {
Test one = new Test();
one.height = 2;
one.width = 1;
Test two = new Test();
two.height = 2;
two.width = 3;
Test three = new Test();
three.height = 1;
three.width = 1;
Comparator<Test> comparator = Comparator
.comparingInt((Test t) -> t.height).reversed()
.thenComparingInt((Test t ) -> t.width).reversed();
List<Test> list = new ArrayList<>();
list.add(one);
list.add(two);
list.add(three);
list.stream()
.sorted(comparator)
.forEach(e -> System.out.println(e.height + "/" + e.width));
}
}
class Test {
int width;
int height;
}
Run Code Online (Sandbox Code Playgroud)
我得到输出:
1/1
2/3
2/1
Run Code Online (Sandbox Code Playgroud)
因为第二个reversed()反转了整个列表。有没有办法让输出:
2/3
2/1
1/1
Run Code Online (Sandbox Code Playgroud)
只是删除reversed()从comparingInt和来电reversed时thenComparingLong:
Comparator<Test> comparator =
Comparator.comparingInt((Test t) -> t.height) // <--- removed reverse from this comparator
.thenComparingLong((Test t ) -> t.width).reversed();
Run Code Online (Sandbox Code Playgroud)
此外,鉴于这width是一个int我会使用thenComparingInt而不是thenComparingLong.
此外,关于您的流管道,我建议您使用,forEachOrdered因为您关心打印元素的顺序。
forEach 记录为:
此操作的行为明显是不确定的。对于并行流管道,此操作不保证遵守流的遇到顺序,因为这样做会牺牲并行性的好处。
所以:
list.stream()
.sorted(comparator)
.forEachOrdered(e -> System.out.println(e.height + "/" + e.width));
Run Code Online (Sandbox Code Playgroud)
为了完成 Aomine 的非常好的答案,我将揭露其背后的可能性和行为。
请注意,与直接字段访问相比,您应该更喜欢 getter(以及方法引用)。所以我会以此来说明。我还将依赖static import静态Comparator方法,例如 import static java.util.Comparator.*;专注于重要的事情。
你所做的实际上取消了最初的Comparator逆转getHeight():
Comparator<Test> comparator =
comparingInt(Test::getHeight)
.reversed() // 1)
.thenComparingInt(Test::getWidth) // 2)
.reversed(); // 3)
Run Code Online (Sandbox Code Playgroud)
从逻辑上来说,这意味着:
1) 通过与 的相反方向比较来排序Test::getHeight。
2)然后通过比较排序Test::getWidth。
3)反转整个比较逻辑。
所以你会得到一个比较器,它对 进行排序Test::getHeight,然后对 进行反向排序Test::getWidth。
Aomine提供的解决方案中:
Comparator<Test> comparator =
comparingInt(Test::getHeight) // 1)
.thenComparingInt(Test::getWidth) // 2)
.reversed(); // 3)
Run Code Online (Sandbox Code Playgroud)
从逻辑上来说,这意味着:
1)通过比较排序Test::getHeight。
2)然后通过比较排序Test::getWidth。
3)反转整个比较逻辑。
因此,您会得到一个按 的相反顺序排序的比较器Test::getHeight,然后按 的相反顺序排序Test::getWidth。
您也可以这样编写代码(虽然比较冗长,但在学习方面很有趣):
Comparator<Test> comparator =
comparingInt(Test::getHeight)
.reversed() // 1)
.thenComparing(comparingInt(Test::getWidth)
.reversed()); // 2)
Run Code Online (Sandbox Code Playgroud)
从逻辑上来说,这意味着:
1) 通过与 的相反方向比较来排序Test::getHeight。
2)然后通过与相反的比较排序Test::getWidth。
这仍然会产生一个比较器,它按 的相反顺序排序Test::getHeight,然后按 的相反顺序排序Test::getWidth。