Como usar um lambda Java8 para classificar um fluxo na ordem inversa?

181

Estou usando o java lambda para classificar uma lista.

como posso classificá-lo de maneira inversa?

Eu vi esse post , mas quero usar o java 8 lambda.

Aqui está o meu código (eu usei * -1) como um 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());
Elad Benda2
fonte
O que você quer dizer com "ordem inversa"? Se você substituir -1 * answerpor answer, o pedido mudará para o reverso do que era -1 * ....
dasblinkenlight
2
Cuidado! Todo o seu código sugere que você deseja usar em forEachOrderedvez deforEach
Holger
por que é que? você pode explicar?
Elad Benda2
1
Siga os links. Basta dizer, forEachOrderedcomo o nome sugere, preocupações sobre a ordem encontro que é relevante como você quiser pular um certo número de mais novos arquivos que conta com a “classificado por data de modificação” fim .
Holger
1
Um pouco tarde, quero reconhecer que seu entendimento de como sortskip→ (não ordenado) forEachdeve funcionar está correto e que de fato foi implementado para funcionar dessa maneira nos JREs de hoje, mas em 2015, quando os comentários anteriores foram feitos, foi realmente um problema (como você pode ler nesta pergunta ).
Holger

Respostas:

218

Você pode adaptar a solução que você vinculou em Como classificar ArrayList <Long> em Java em ordem decrescente? envolvendo-o em uma lambda:

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

observe que f2 é o primeiro argumento de Long.compare, não o segundo, portanto o resultado será revertido.

Adrian Leonhard
fonte
224
... ouComparator.comparingLong(File::lastModified).reversed()
Holger
3
@Holger Stream of String, e com comparingLong(v->Long.valueOf(v)).reversed()lança compilação de erro: java.lang.valueOf(java.lang.String) cannot be used on java.lang.valueOf(java.lang.Object). Por quê?
Tiina
3
@ Tiina: veja Comparator.reversed () não compila usando lambda . Você pode tentar comparingLong(Long::valueOf).reversed(). OuCollections.reverseOrder(comparingLong(v->Long.valueOf(v)))
Holger
@ Holger obrigado pelo link. Mas o Stuart "não sabe ao certo por quê". Fiquei confuso quando vi os dois métodos se referirem em Tvez de Object, o que significa que o tipo de objeto não deve ser perdido. Mas na verdade é. É disso que estou confuso.
Tiina
3
@ Tiina: é a propagação de retorno do tipo de destino que não funciona. Se a expressão inicial da sua cadeia tiver um tipo independente, ela funcionará na cadeia como antes do Java 8. Como você pode ver no exemplo do comparador, usando uma referência de método, ou seja comparingLong(Long::valueOf).reversed(), funciona, da mesma forma uma expressão lambda de tipo explícito funciona comparingLong((String v) -> Long.valueOf(v)).reversed()funciona. Também Stream.of("foo").mapToInt(s->s.length()).sum()funciona, pois "foo"fornece o tipo independente enquanto Stream.of().mapToInt(s-> s.length()).sum()falha.
Holger
170

Se seus elementos de fluxo implementarem Comparable, a solução se tornará mais simples:

 ...stream()
 .sorted(Comparator.reverseOrder())
Grigory Kislin
fonte
3
ou...stream().max(Comparator.naturalOrder())
Philippe
1
Para o elemento mais recente em uma coleção comparar por data.stream().max(Comparator.comparing(Clazz::getDate))
Marco Pelegrini
1
E se os elementos não forem Comparable. Collections.reversenão possui essa restrição.
Wilmol 01/10/19
63

Usar

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

Então

.forEach(item -> item.delete());
Vishnudev K
fonte
3
Bem, ele perguntou sobre fluxos, mas eu gosto da sua resposta, no entanto.
Tim Büthe
Esta não é a maneira "funcional" de fazê-lo ... tem efeitos colaterais !!
programador
38

Você pode usar uma referência de método:

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());

Em alternativa à referência do método, você pode usar uma expressão lambda, portanto, o argumento da comparação se torna:

.sorted(comparing(file -> file.lastModified()).reversed());
iFederx
fonte
19

Compartilhamento de maneira alternativa:

ASC

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

DESC

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

Isso pode ser feito facilmente usando o Java 8 e o uso de um comparador reverso .

Criei uma lista de arquivos a partir de um diretório, que exibi sem classificação, classificação e classificação reversa usando um comparador simples para a classificação e, em seguida, chamando reversed () para obter a versão reversa desse comparador.

Veja o código abaixo:

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());
        }
    }
}
ManoDestra
fonte
3

Classificar lista de arquivos com java 8 Collections

Exemplo de como usar o Java 8 do Collections and Comparator para classificar uma lista de arquivos.

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()));
    }
}
Jonathan Mendoza
fonte
1

Em simples, usando Comparador e Cobrança você pode classificar como abaixo na reversão fim usando JAVA 8

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

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

Para classificação inversa, basta alterar a ordem de x1, x2 para chamar o método x1.compareTo (x2), o resultado será inverso entre si.

Pedido padrão

List<String> sortedByName = citiesName.stream().sorted((s1,s2)->s1.compareTo(s2)).collect(Collectors.toList());
System.out.println("Sorted by Name : "+ sortedByName);

Ordem reversa

List<String> reverseSortedByName = citiesName.stream().sorted((s1,s2)->s2.compareTo(s1)).collect(Collectors.toList());
System.out.println("Reverse Sorted by Name : "+ reverseSortedByName );
Jimmy
fonte