CodeGym /Corsi /JAVA 25 SELF /Trasformazione delle collezioni

Trasformazione delle collezioni

JAVA 25 SELF
Livello 28 , Lezione 1
Disponibile

1. Trasformazione degli elementi delle collezioni

In programmazione una delle operazioni più frequenti è la trasformazione di una collezione: abbiamo una collezione di dati di un tipo e, sulla sua base, dobbiamo crearne una nuova di un altro tipo. Per esempio, da un elenco di oggetti di tipo User ottenere l’elenco dei loro nomi (String), oppure da un elenco di numeri l’elenco dei loro quadrati.

Il modo più fondamentale e comprensibile in Java è usare l’approccio imperativo, cioè un normale ciclo for (spesso — for-each).

Esempio: ottenere la lista delle lunghezze a partire da una lista di stringhe

Supponiamo di avere un elenco di nomi di città:

List<String> cities = List.of("Londra", "Parigi", "Tokyo", "New York");

Il nostro compito è creare un nuovo elenco che contenga la lunghezza di ogni nome. Il risultato finale dovrebbe essere: [6, 6, 5, 8].

Soluzione con un ciclo for:

import java.util.ArrayList;
import java.util.List;

public class CollectionTransform {
    public static void main(String[] args) {
        List<String> cities = List.of("Londra", "Parigi", "Tokyo", "New York");
        List<Integer> lengths = new ArrayList<>(); // Creiamo una nuova lista vuota per il risultato

        for (String city : cities) {
            // Per ogni elemento di cities calcoliamo la sua lunghezza...
            int length = city.length();
            // ...e aggiungiamo questo risultato al nuovo elenco
            lengths.add(length);
        }

        System.out.println(lengths); // Stamperà: [6, 6, 5, 8]
    }
}

Iniziamo creando una nuova collezione vuota per i risultati — la trasformazione non modifica la collezione di origine. Per iterare sull’originale usiamo un ciclo for-each e all’interno applichiamo la logica necessaria (length()) a ogni elemento, aggiungendo il risultato al nuovo elenco tramite add.

2. Trasformazione di oggetti

Spesso lavoriamo con tipi di dati più complessi. Supponiamo di avere una classe Product e di dover ottenere l’elenco dei suoi nomi (o dei prezzi).

public class Product {
    private String name;
    private double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }
}

Ora, avendo l’elenco dei prodotti, otteniamo l’elenco dei loro nomi:

import java.util.ArrayList;
import java.util.List;

public class ProductExample {
    public static void main(String[] args) {
        List<Product> products = List.of(
            new Product("Portatile", 1200.0),
            new Product("Mouse", 25.5),
            new Product("Tastiera", 75.0)
        );

        // Creiamo una nuova lista per i nomi
        List<String> productNames = new ArrayList<>();

        for (Product product : products) {
            // Per ogni oggetto Product otteniamo il suo nome
            productNames.add(product.getName());
        }

        System.out.println(productNames); // Stamperà: [Portatile, Mouse, Tastiera]
    }
}

La logica è la stessa: iteriamo sulla collezione di origine, applichiamo a ogni elemento il metodo desiderato (ad esempio, getName()) e aggiungiamo il risultato alla nuova collezione.

3. Lavorare con collezioni annidate

Consideriamo il caso di un elenco di elenchi: più reparti, ognuno con il proprio elenco di dipendenti. L’obiettivo è ottenere un unico elenco («piatto») di tutti i dipendenti.

Esempio: unione degli elenchi di dipendenti

List<List<String>> departments = List.of(
    List.of("Anna", "Boris"),
    List.of("Viktoriya", "Gleb", "Dmitriy"),
    List.of("Elena")
);

Vogliamo ottenere un’unica lista: [Anna, Boris, Viktoriya, Gleb, Dmitriy, Elena].

Metodo 1: con il metodo addAll()

import java.util.ArrayList;
import java.util.List;

public class NestedCollectionExample {
    public static void main(String[] args) {
        List<List<String>> departments = List.of(
            List.of("Anna", "Boris"),
            List.of("Viktoriya", "Gleb", "Dmitriy"),
            List.of("Elena")
        );

        List<String> allEmployees = new ArrayList<>();

        // Iteriamo su ogni lista (reparto)
        for (List<String> department : departments) {
            // Aggiungiamo tutti gli elementi della lista corrente all’elenco generale
            allEmployees.addAll(department);
        }

        System.out.println(allEmployees); // [Anna, Boris, Viktoriya, Gleb, Dmitriy, Elena]
    }
}

Metodo 2: ciclo annidato — lo stesso, ma «a mano»:

List<List<String>> departments = List.of(...);
List<String> allEmployees = new ArrayList<>();

for (List<String> department : departments) { // Ciclo esterno sui reparti
    for (String employee : department) {      // Ciclo interno sui dipendenti
        allEmployees.add(employee);
    }
}

System.out.println(allEmployees);

Entrambi i metodi sono equivalenti nel risultato. Il metodo addAll() in sostanza incapsula la logica del ciclo annidato e rende il codice più conciso.

4. Casi complessi e trasformazioni con condizioni

A volte la trasformazione va eseguita solo per gli elementi che soddisfano una condizione. Per esempio, ottenere l’elenco dei nomi delle città che iniziano con la lettera "N" e prenderne le lunghezze. Qui combiniamo filtraggio e trasformazione: if + chiamata del metodo (length()).

import java.util.ArrayList;
import java.util.List;

public class ConditionalTransform {
    public static void main(String[] args) {
        List<String> cities = List.of("Londra", "Parigi", "Tokyo", "New York", "Norimberga");
        List<Integer> lengths = new ArrayList<>();

        for (String city : cities) {
            // Prima controlliamo la condizione
            if (city.startsWith("N")) {
                // Se la condizione è soddisfatta, applichiamo la trasformazione
                lengths.add(city.length());
            }
        }

        System.out.println(lengths); // Stamperà: [8, 10]
    }
}

Il modello è questo: all’interno del ciclo prima filtriamo l’elemento tramite una condizione (startsWith, confronto, controllo di intervallo, ecc.), poi applichiamo la trasformazione necessaria e mettiamo il risultato nel nuovo elenco.

5. Errori tipici e insidie

Errore n. 1: modificare la collezione di origine durante l’iterazione. Un errore frequente è tentare di aggiungere/rimuovere elementi dalla collezione originaria direttamente nel ciclo for-each. Questo porta a errori e comportamenti imprevedibili. Soluzione: create sempre un nuovo elenco per i risultati e riempitelo.

Errore n. 2: cast errato. Se lavorate con collezioni “raw” (per esempio tramite Object) e fate il cast a un tipo errato, otterrete ClassCastException. Usate i generics (List<T>) e rispettate le firme dei metodi.

Errore n. 3: uso inefficiente delle risorse. Per collezioni molto grandi, creare continuamente nuovi elenchi e copiare elementi può incidere su memoria e tempo. Nella maggior parte dei compiti quotidiani è accettabile, ma quando trattate grandi volumi di dati considerate la complessità e, se necessario, ottimizzate l’approccio.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION