Ordinare lista con gli stream

di il
7 risposte

Ordinare lista con gli stream

Salve,
per una serie di motivi non posso ordinare la mia lista direttamente con la query, così come non posso paginarla, devo fare quindi un lavoro in partenza.

Dal mio result set mi creo la lista.
A questo punto la ordino, ho applicato questa soluzione:
List<myDTO> totale = totaleElementi.stream().sorted(Comparator.comparing(myDTO::getNome).reversed())).collect(Collectors.toList()); 
dove totaleElementi è il risultato della query a DB. vi torna che equivale ad un "order by nome desc" ? E' una soluzione affidabile/valida per fare quello di cui ho bisogno? E se volessi ordinare per nome e per cognome? Un order by nome desc , cognome desc? ho provato ma non mi ordina più...

7 Risposte

  • Re: Ordinare lista con gli stream

    Guarda che NON serve uno stream solo per ordinare una lista. Da Java 8 List ha il sort() a cui si passa anche un Comparator (che puoi fare esattamente come stavi facendo con Comparator.comparing ecc....)

    Naturalmente esiste ancora il buon "vecchio" Collections.sort()
  • Re: Ordinare lista con gli stream

    andbin ha scritto:


    Guarda che NON serve uno stream solo per ordinare una lista. Da Java 8 List ha il sort() a cui si passa anche un Comparator (che puoi fare esattamente come stavi facendo con Comparator.comparing ecc....)

    Naturalmente esiste ancora il buon "vecchio" Collections.sort()
    Bhe diciamo che la politica del team prevede l'utilizzo degli Stream (che sto imparando a conoscere in questi giorni) per ogni cosa da fare, quindi mi adeguo. Però se risucissi ad ordinare per dire per nome e per cognome, non mi farei problemi a cambiare, mal che vada becco una lamentela, ma vedo che ho lo stesso problema, non riesco a replicare "order by nome desc, cognome desc"
  • Re: Ordinare lista con gli stream

    Test90 ha scritto:


    Bhe diciamo che la politica del team prevede l'utilizzo degli Stream per ogni cosa da fare
    Allora: Stream "per ogni cosa" è un po' brutto/vago come approccio.

    Per le liste, l'ordinamento da stream può avere senso SE:
    - la lista non sai da dove arriva e/o sai o presumi che è "immutabile"
    - la lista originale per vari motivi non deve essere toccata e ne devi creare un'altra ordinata

    Test90 ha scritto:


    non riesco a replicare "order by nome desc, cognome desc"
    Semplicemente:
    Comparator.comparing(myDTO::getNome).thenComparing(myDTO::getCognome).reversed()
    Questa espressione dà un Comparator che puoi usare ovunque si possa ordinare: lista.sort(comp) / Collections.sort(lista, comp) / unStream.sorted(comp)



    NOTA: se hai provato a fare:

    Comparator.comparing(myDTO::getNome).reversed().thenComparing(myDTO::getCognome).reversed()

    è giusto tecnicamente ma NON ti dà quello che volevi (nome desc, cognome desc).
    Questi metodi thenComparing() e reversed() funzionano per incapsulamento ovvero ciascuno restituisce un nuovo oggetto Comparator che "incapsula" il Comparator dello step precedente.
    Quindi l'ultimo reversed() fa concettualmente il reverse del primo reversed() ed ottieni "nome ASC, cognome desc"

    Mentre la soluzione detta all'inizio fa un singolo reversed() finale e questo "gira" il senso per entrambe le comparazioni precedenti.
  • Re: Ordinare lista con gli stream

    andbin ha scritto:



    Allora: Stream "per ogni cosa" è un po' brutto/vago come approccio.

    Per le liste, l'ordinamento da stream può avere senso SE:
    - la lista non sai da dove arriva e/o sai o presumi che è "immutabile"
    - la lista originale per vari motivi non deve essere toccata e ne devi creare un'altra ordinata

    Test90 ha scritto:


    non riesco a replicare "order by nome desc, cognome desc"
    Semplicemente:
    Comparator.comparing(myDTO::getNome).thenComparing(myDTO::getCognome).reversed()
    Questa espressione dà un Comparator che puoi usare ovunque si possa ordinare: lista.sort(comp) / Collections.sort(lista, comp) / unStream.sorted(comp)



    NOTA: se hai provato a fare:

    Comparator.comparing(myDTO::getNome).reversed().thenComparing(myDTO::getCognome).reversed()

    è giusto tecnicamente ma NON ti dà quello che volevi (nome desc, cognome desc).
    Questi metodi thenComparing() e reversed() funzionano per incapsulamento ovvero ciascuno restituisce un nuovo oggetto Comparator che "incapsula" il Comparator dello step precedente.
    Quindi l'ultimo reversed() fa concettualmente il reverse del primo reversed() ed ottieni "nome ASC, cognome desc"

    Mentre la soluzione detta all'inizio fa un singolo reversed() finale e questo "gira" il senso per entrambe le comparazioni precedenti.
    Pensa che usiamo gli stream pure per avere la dimensione della lista...
    Comunque capito, quindi si commettevo l'errore descritto da te. Quindi se deve essere asc il primo ma desc il secondo, devo mettere il reverse ad entrambi così che l'ultimo poi fa agire il primo al contrario. Il problema però si presenta se da fe mi arrivano 4 campi da ordinare del tipo asc, asc, desc, desc o qualsiasi altra combinazione...
  • Re: Ordinare lista con gli stream

    Test90 ha scritto:


    Pensa che usiamo gli stream pure per avere la dimensione della lista...
    Ma veramente??

    Test90 ha scritto:


    Il problema però si presenta se da fe mi arrivano 4 campi da ordinare del tipo asc, asc, desc, desc o qualsiasi altra combinazione...
    Una soluzione molto semplice per evitare la questione della "catena" di comparatori che non rende molto facile/espressivo il senso di più/vari reverse, potrebbe essere quella di fare un metodo del tipo (butto lì, scritto al volo):
    public class MyComparatorUtils {            //nome a scelta
        private MyComparatorUtils() {}
    
        @SafeVarargs
        public static <T> Comparator<T> comparatorOf(Comparator<T>... comparators) {
            return (e1, e2) -> {
                for (Comparator<T> c : comparators) {
                    int r = c.compare(e1, e2);
                    if (r != 0) {
                        return r;
                    }
                }
    
                return 0;
            };
        }
    }

    Così da poter fare es. (con ipotetica classe Persona):
    MyComparatorUtils.comparatorOf(
        Comparator.comparing(Persona::getNome),
        Comparator.comparing(Persona::getCognome).reversed(),
        Comparator.comparingInt(Persona::getAnnoNascita))
    Quindi concettualmente: nome ASC, cognome DESC, annoNascita ASC


    Ma ci potrebbero essere anche ben altri "design". Ad esempio fare una classe di "builder" per Comparator che costruisce un comparatore replicando (meglio) i concetti dei comparing di Comparator.
  • Re: Ordinare lista con gli stream

    andbin ha scritto:



    Una soluzione molto semplice per evitare la questione della "catena" di comparatori che non rende molto facile/espressivo il senso di più/vari reverse, potrebbe essere quella di fare un metodo del tipo (butto lì, scritto al volo):
    public class MyComparatorUtils {            //nome a scelta
        private MyComparatorUtils() {}
    
        @SafeVarargs
        public static <T> Comparator<T> comparatorOf(Comparator<T>... comparators) {
            return (e1, e2) -> {
                for (Comparator<T> c : comparators) {
                    int r = c.compare(e1, e2);
                    if (r != 0) {
                        return r;
                    }
                }
    
                return 0;
            };
        }
    }

    Così da poter fare es. (con ipotetica classe Persona):
    MyComparatorUtils.comparatorOf(
        Comparator.comparing(Persona::getNome),
        Comparator.comparing(Persona::getCognome).reversed(),
        Comparator.comparingInt(Persona::getAnnoNascita))
    Quindi concettualmente: nome ASC, cognome DESC, annoNascita ASC


    Ma ci potrebbero essere anche ben altri "design". Ad esempio fare una classe di "builder" per Comparator che costruisce un comparatore replicando (meglio) i concetti dei comparing di Comparator.
    Grazie per i consigli, spero mi diano il we per implementare la soluzione, perché mi devo andare a studiare il tutto un po' meglio.
  • Re: Ordinare lista con gli stream

    Test90 ha scritto:


    andbin ha scritto:



    Una soluzione molto semplice per evitare la questione della "catena" di comparatori che non rende molto facile/espressivo il senso di più/vari reverse, potrebbe essere quella di fare un metodo del tipo (butto lì, scritto al volo):
    public class MyComparatorUtils {            //nome a scelta
        private MyComparatorUtils() {}
    
        @SafeVarargs
        public static <T> Comparator<T> comparatorOf(Comparator<T>... comparators) {
            return (e1, e2) -> {
                for (Comparator<T> c : comparators) {
                    int r = c.compare(e1, e2);
                    if (r != 0) {
                        return r;
                    }
                }
    
                return 0;
            };
        }
    }

    Così da poter fare es. (con ipotetica classe Persona):
    MyComparatorUtils.comparatorOf(
        Comparator.comparing(Persona::getNome),
        Comparator.comparing(Persona::getCognome).reversed(),
        Comparator.comparingInt(Persona::getAnnoNascita))
    Quindi concettualmente: nome ASC, cognome DESC, annoNascita ASC


    Ma ci potrebbero essere anche ben altri "design". Ad esempio fare una classe di "builder" per Comparator che costruisce un comparatore replicando (meglio) i concetti dei comparing di Comparator.
    Grazie per i consigli, spero mi diano il we per implementare la soluzione, perché mi devo andare a studiare il tutto un po' meglio.
Devi accedere o registrarti per scrivere nel forum
7 risposte