如何使用Java8的lambda表达式将流按相反顺序排序?

267

我正在使用Java Lambda对列表进行排序。

如何以相反的方式进行排序?

我看到了这篇帖子,但我想使用Java 8 Lambda。

这是我的代码(我使用*-1作为hack):

Arrays.asList(files).stream()
    .filter(file -> isNameLikeBaseLine(file, baseLineFile.getName()))
    .sorted(new Comparator<File>() {
        public int compare(File o1, File o2) {
            int answer;
            if (o1.lastModified() == o2.lastModified()) {
                answer = 0;
            } else if (o1.lastModified() > o2.lastModified()) {
                answer = 1;
            } else {
                answer = -1;
            }
            return -1 * answer;
        }
    })
    .skip(numOfNewestToLeave)
    .forEach(item -> item.delete());

“Reverse order” 是什么意思?如果你将“-1 * answer” 替换为 “answer”,顺序将会变成与 “-1 * ...” 的相反。 - Sergey Kalinichenko
2
жіЁж„ҸпјҒдҪ зҡ„жүҖжңүд»Јз ҒйғҪиЎЁжҳҺдҪ жғідҪҝз”Ё forEachOrdered иҖҢдёҚжҳҜ forEachгҖӮ - Holger
为什么那样?你能解释一下吗? - Elad Benda2
1
跟随链接。简单来说,“forEachOrdered”正如其名称所示,关心遇到的顺序,这很重要,因为您想要跳过一定数量的最新文件,这依赖于“按修改时间排序”的顺序 - Holger
我不是很明白。因为在我的例子中,forEach 是在 skip 之后执行的,也就是说,在我的筛选过滤之后,我并不关心顺序。 - Elad Benda2
1
略晚了一些,但我想承认你对于 sortskip → (unordered) forEach 如何工作的理解是正确的,并且在今天的 JREs 中确实是这样实现的,但是在2015年之前,当前面的评论被提出时,这确实是一个问题(你可以在 这个问题 中了解更多)。 - Holger
13个回答

298
您可以通过将链接中提供的解决方案包装在lambda表达式中来适应您的需求:如何在Java中按降序排序ArrayList<Long>:

.sorted((f1, f2) -> Long.compare(f2.lastModified(), f1.lastModified())

请注意,f2Long.compare的第一个参数,而不是第二个参数,因此结果将被反转。

330
或者 Comparator.comparingLong(File::lastModified).reversed() 的意思是使用文件的最后修改时间进行倒序排序。 - Holger
7
为什么在使用Stream的comparingLong(v->Long.valueOf(v)).reversed()时会出现编译错误,提示java.lang.valueOf(java.lang.String)不能用于java.lang.valueOf(java.lang.Object) - Tiina
7
@Tiina:请参考Comparator.reversed() does not compile using lambda。你可以尝试使用comparingLong(Long::valueOf).reversed(),或者使用Collections.reverseOrder(comparingLong(v->Long.valueOf(v))) - Holger
@Holger 感谢分享链接。但 Stuart 说“我不太确定为什么”。当我看到两种方法都是引用 T 而不是 Object 时,表示对象类型不应该丢失,但实际上确实丢失了。这就是我感到困惑的原因。 - Tiina
4
@Tiina:无法逆推目标类型。如果您链的初始表达式具有独立的类型,则该链会像Java 8之前一样工作。如您可以在比较器示例中看到,使用方法引用comparingLong(Long::valueOf).reversed()也可以工作,同样显式类型的lambda表达式也可以工作comparingLong((String v) -> Long.valueOf(v)).reversed()。此外,Stream.of("foo").mapToInt(s->s.length()).sum()可以工作,因为“foo”提供了独立的类型,而Stream.of().mapToInt(s-> s.length()).sum()则失败。 - Holger
显示剩余4条评论

283
如果你的流元素实现了Comparable接口,那么解决方案就变得更简单了。
 ...stream()
 .sorted(Comparator.reverseOrder())

11
或者 ...stream().max(Comparator.naturalOrder()) - Philippe
3
对于集合中最新的元素,按照日期比较可以使用.stream().max(Comparator.comparing(Clazz::getDate)) - Marco Pelegrini
4
如果元素不是可比较的,那该怎么办?Collections.reverse方法并没有这样的限制。 - wilmol

85

使用

Comparator<File> comparator = Comparator.comparing(File::lastModified); 
Collections.sort(list, comparator.reversed());

然后

.forEach(item -> item.delete());

3
好的,他问的是关于流的问题,但我仍然喜欢您的回答。 - Tim Büthe
这不是“函数式”的做法...它有副作用!! - TriCore

61

你可以使用方法引用:

import static java.util.Comparator.*;
import static java.util.stream.Collectors.*;

Arrays.asList(files).stream()
    .filter(file -> isNameLikeBaseLine(file, baseLineFile.getName()))
    .sorted(comparing(File::lastModified).reversed())
    .skip(numOfNewestToLeave)
    .forEach(item -> item.delete());

在不使用方法引用的情况下,您可以使用lambda表达式,因此比较的参数变为:

.sorted(comparing(file -> file.lastModified()).reversed());

34

另一种分享方式:

ASC

List<Animal> animals = this.service.findAll();
animals = animals.stream().sorted(Comparator.comparing(Animal::getName)).collect(Collectors.toList());

描述

List<Animal> animals = this.service.findAll();
animals = animals.stream().sorted(Comparator.comparing(Animal::getName).reversed()).collect(Collectors.toList());

14
简单来说,使用 Comparator 和 Collection,您可以在 JAVA 8 中按以下方式以逆序排序。
import java.util.Comparator;;
import java.util.stream.Collectors;

Arrays.asList(files).stream()
    .sorted(Comparator.comparing(File::getLastModified).reversed())
    .collect(Collectors.toList());

请确保您已经重写了带有hashCode()equals方法的对象,否则上述代码将无法正常工作。

4

使用Java 8和一个反转的Comparator,这很容易实现。

我从一个目录创建了文件列表,并使用简单的Comparator对其进行了未排序、排序和反向排序。然后调用reversed()来获取该Comparator的反向版本。

请参见下面的代码:

package test;

import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

public class SortTest {
    public static void main(String... args) {
        File directory = new File("C:/Media");
        File[] files = directory.listFiles();
        List<File> filesList = Arrays.asList(files);

        Comparator<File> comparator = Comparator.comparingLong(File::lastModified);
        Comparator<File> reverseComparator = comparator.reversed();

        List<File> forwardOrder = filesList.stream().sorted(comparator).collect(Collectors.toList());
        List<File> reverseOrder = filesList.stream().sorted(reverseComparator).collect(Collectors.toList());

        System.out.println("*** Unsorted ***");
        filesList.forEach(SortTest::processFile);

        System.out.println("*** Sort ***");
        forwardOrder.forEach(SortTest::processFile);

        System.out.println("*** Reverse Sort ***");
        reverseOrder.forEach(SortTest::processFile);
    }

    private static void processFile(File file) {
        try {
            if (file.isFile()) {
                System.out.println(file.getCanonicalPath() + " - " + new Date(file.lastModified()));
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

3

使用Java 8的Collections和Comparator对文件列表进行排序的示例。

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class ShortFile {

    public static void main(String[] args) {
        List<File> fileList = new ArrayList<>();
        fileList.add(new File("infoSE-201904270100.txt"));
        fileList.add(new File("infoSE-201904280301.txt"));
        fileList.add(new File("infoSE-201904280101.txt"));
        fileList.add(new File("infoSE-201904270101.txt"));

        fileList.forEach(x -> System.out.println(x.getName()));
        Collections.sort(fileList, Comparator.comparing(File::getName).reversed());
        System.out.println("===========================================");
        fileList.forEach(x -> System.out.println(x.getName()));
    }
}

3

使用Lambda表达式进行反向排序的这个简单步骤.sorted(Comparator.reverseOrder()),可以避免所有这些复杂性。

Arrays.asList(files).stream()
.filter(file -> isNameLikeBaseLine(file, baseLineFile.getName()))
.sorted(Comparator.reverseOrder()).skip(numOfNewestToLeave)
.forEach(item -> item.delete());

不太清楚,请解释一下。 - Sathish Kumar k k

1
    //sort Stream in reverse oreder with using Lambda Expressrion.

    List<String> list = Arrays.asList("Ram","Rahul","Ravi","Vishal","Vaibhav","Rohit","Harit","Raghav","Shubhan");
    List<String> sortedListLambda = list.stream().sorted((x,y)->y.compareTo(x)).collect(Collectors.toList());
    System.out.println(sortedListLambda);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接