Come utilizzare un lambda Java8 per ordinare un flusso in ordine inverso?


181

Sto usando Java Lambda per ordinare un elenco.

come posso ordinarlo al contrario?

Ho visto questo post , ma voglio usare java 8 lambda.

Ecco il mio codice (ho usato * -1) come 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());

Cosa intendi con "ordine inverso"? Se lo sostituisci -1 * answercon answer, l'ordine cambierà al contrario di quello che era -1 * ....
dasblinkenlight,

2
Attenzione! Tutto il tuo codice suggerisce che vuoi usare forEachOrderedinvece diforEach
Holger

perché? Puoi spiegare?
Elad Benda2,

1
Segui i link. Detto semplicemente forEachOrdered, come suggerisce il nome, ci tiene all'ordine degli incontri che è rilevante in quanto si desidera saltare un certo numero di file più recenti che si basa sull'ordine "ordinato per tempo di modifica" .
Holger,

1
Un po 'tardi, voglio riconoscere che la tua comprensione di come sortskip→ (non ordinata) forEachdovrebbe funzionare, è corretta e che è effettivamente implementata per funzionare in questo modo nei JRE di oggi, ma nel 2015, quando sono stati fatti i commenti precedenti, era davvero un problema (come puoi leggere in questa domanda ).
Holger

Risposte:


218

È possibile adattare la soluzione collegata in Come ordinare ArrayList <Lungo> in Java in ordine decrescente? avvolgendolo in una lambda:

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

nota che f2 è il primo argomento Long.compare, non il secondo, quindi il risultato sarà invertito.


224
... oppureComparator.comparingLong(File::lastModified).reversed()
Holger,

3
@Holger flusso di stringa, e avendo comparingLong(v->Long.valueOf(v)).reversed()getta errore di compilazione: java.lang.valueOf(java.lang.String) cannot be used on java.lang.valueOf(java.lang.Object). Perché?
Tiina,

3
@Tiina: vedi Comparator.reversed () non compilare usando lambda . Puoi provare comparingLong(Long::valueOf).reversed()invece. OppureCollections.reverseOrder(comparingLong(v->Long.valueOf(v)))
Holger,

@Holger grazie per il link. Ma lo Stuart "non è del tutto sicuro del perché". Ero confuso quando ho visto fare riferimento a entrambi i metodi Tanziché Object, il che significa che il tipo di oggetto non dovrebbe essere perso. Ma in realtà lo è. Questo è ciò di cui sono confuso.
Tiina,

3
@Tiina: è la propagazione inversa del tipo di destinazione che non funziona. Se l'espressione iniziale della tua catena ha un tipo autonomo, funziona attraverso la catena come prima di Java 8. Come puoi vedere nell'esempio di confronto, usando un riferimento al metodo, ovvero comparingLong(Long::valueOf).reversed()funziona, allo stesso modo un'espressione lambda tipizzata in modo esplicito funziona comparingLong((String v) -> Long.valueOf(v)).reversed()funziona. Stream.of("foo").mapToInt(s->s.length()).sum()Funziona anche , poiché "foo"fornisce il tipo autonomo mentre Stream.of().mapToInt(s-> s.length()).sum()fallisce.
Holger,

170

Se i tuoi elementi di flusso vengono implementati, Comparablela soluzione diventa più semplice:

 ...stream()
 .sorted(Comparator.reverseOrder())

3
oppure...stream().max(Comparator.naturalOrder())
Philippe,

1
Per l'elemento più recente di una raccolta che confronta per data.stream().max(Comparator.comparing(Clazz::getDate))
Marco Pelegrini,

1
E se gli elementi non lo fossero Comparable. Collections.reversenon ha una tale limitazione.
Wilmol,

63

Uso

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

Poi

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

3
Bene, mi ha chiesto dei flussi, ma mi piace comunque la tua risposta.
Tim Büthe

Questo non è un modo "funzionale" di farlo ... ha effetti collaterali !!
Programmatore

38

È possibile utilizzare un riferimento al metodo:

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

In alternativa al metodo di riferimento puoi usare un'espressione lambda, quindi l'argomento del confronto diventa:

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

19

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

4

Questo può essere fatto facilmente usando Java 8 e l'uso di un comparatore invertito .

Ho creato un elenco di file da una directory, che visualizzo non ordinati, ordinati e in ordine inverso usando un semplice comparatore per l'ordinamento e quindi chiamando reversed () su di esso per ottenere la versione inversa di quel comparatore.

Vedi il codice qui sotto:

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

Ordina l'elenco dei file con java 8 Collections

Esempio su come utilizzare le raccolte e il comparatore Java 8 per ordinare un elenco di file.

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

1

In parole semplici, usando Comparator and Collection puoi ordinare come sotto in ordine inverso 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());

0

Per l'ordinamento inverso basta cambiare l'ordine di x1, x2 per chiamare il metodo x1.compareTo (x2) il risultato sarà invertito l'uno con l'altro

Ordine predefinito

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

Ordine inverso

List<String> reverseSortedByName = citiesName.stream().sorted((s1,s2)->s2.compareTo(s1)).collect(Collectors.toList());
System.out.println("Reverse Sorted by Name : "+ reverseSortedByName );
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.