CodeGym /Cursos /JAVA 25 SELF /Transformación de colecciones

Transformación de colecciones

JAVA 25 SELF
Nivel 28 , Lección 1
Disponible

1. Transformación de elementos de colecciones

En programación, una de las operaciones más frecuentes es la transformación de colecciones: tenemos una colección de datos de un tipo y, a partir de ella, debemos crear una nueva colección de otro tipo. Por ejemplo, a partir de una lista de objetos de tipo User obtener la lista de sus nombres (String), o a partir de una lista de números — la lista de sus cuadrados.

La forma más fundamental y comprensible en Java es usar el enfoque imperativo, es decir, un bucle for (a menudo — for-each).

Ejemplo: obtener la lista de longitudes a partir de una lista de cadenas

Supongamos que tenemos una lista de nombres de ciudades:

List<String> cities = List.of("Londres", "París", "Tokio", "Nueva York");

Nuestro objetivo es crear una nueva lista que contenga la longitud de cada nombre. El resultado final debería ser: [7, 5, 5, 10].

Solución con un bucle for:

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

public class CollectionTransform {
    public static void main(String[] args) {
        List<String> cities = List.of("Londres", "París", "Tokio", "Nueva York");
        List<Integer> lengths = new ArrayList<>(); // Creamos una nueva lista vacía para el resultado

        for (String city : cities) {
            // Para cada elemento de cities calculamos su longitud...
            int length = city.length();
            // ...y añadimos ese resultado a la nueva lista
            lengths.add(length);
        }

        System.out.println(lengths); // Mostrará: [7, 5, 5, 10]
    }
}

Empezamos creando una nueva colección vacía para los resultados — la transformación no modifica la colección original. Para recorrer la colección de origen usamos un bucle for-each y dentro aplicamos la lógica necesaria (length()) a cada elemento, y añadimos el resultado a la nueva lista con add.

2. Transformación de objetos

A menudo trabajamos con tipos de datos más complejos. Supongamos que tenemos una clase Product, y necesitamos obtener la lista de sus nombres (o de sus precios).

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

Ahora, teniendo una lista de productos, obtendremos la lista de sus nombres:

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

public class ProductExample {
    public static void main(String[] args) {
        List<Product> products = List.of(
            new Product("Portátil", 1200.0),
            new Product("Ratón", 25.5),
            new Product("Teclado", 75.0)
        );

        // Creamos una nueva lista para los nombres
        List<String> productNames = new ArrayList<>();

        for (Product product : products) {
            // Para cada objeto Product obtenemos su nombre
            productNames.add(product.getName());
        }

        System.out.println(productNames); // Mostrará: [Portátil, Ratón, Teclado]
    }
}

La lógica es la misma: iteramos por la colección de origen, aplicamos a cada elemento el método necesario (por ejemplo, getName()) y añadimos el resultado a la nueva colección.

3. Trabajo con colecciones anidadas

Consideremos el caso de una lista de listas: varios departamentos, cada uno con su propia lista de empleados. La tarea es obtener una única lista («plana») con todos los empleados.

Ejemplo: unir listas de empleados

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

Queremos obtener una única lista: [Anna, Boris, Victoria, Gleb, Dmitry, Elena].

Método 1: mediante el método 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("Victoria", "Gleb", "Dmitry"),
            List.of("Elena")
        );

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

        // Iteramos por cada lista (departamento)
        for (List<String> department : departments) {
            // Añadimos todos los elementos de la lista actual a la lista general
            allEmployees.addAll(department);
        }

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

Método 2: bucle anidado — lo mismo, pero «a mano»:

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

for (List<String> department : departments) { // Bucle externo por departamentos
    for (String employee : department) {      // Bucle interno por empleados
        allEmployees.add(employee);
    }
}

System.out.println(allEmployees);

Ambos métodos son equivalentes en cuanto al resultado. El método addAll() básicamente encapsula la lógica del bucle anidado y hace el código más corto.

4. Casos complejos y transformaciones con condiciones

A veces la transformación debe realizarse solo para los elementos que cumplen una condición. Por ejemplo, obtener la lista de nombres de ciudades que empiezan por la letra "N", y tomar sus longitudes. Aquí combinamos filtrado y transformación: if + llamada a método (length()).

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

public class ConditionalTransform {
    public static void main(String[] args) {
        List<String> cities = List.of("Londres", "París", "Tokio", "Nueva York", "Núremberg");
        List<Integer> lengths = new ArrayList<>();

        for (String city : cities) {
            // Primero comprobamos la condición
            if (city.startsWith("N")) {
                // Si se cumple la condición, aplicamos la transformación
                lengths.add(city.length());
            }
        }

        System.out.println(lengths); // Mostrará: [10, 9]
    }
}

El patrón es el siguiente: dentro del bucle primero filtramos el elemento mediante una condición (startsWith, comparación, comprobación de rango, etc.), luego aplicamos la transformación necesaria y ponemos el resultado en la nueva lista.

5. Errores típicos y escollos

Error n.º 1: modificar la colección de origen durante la iteración. Un error frecuente es intentar añadir/eliminar elementos de la colección de origen directamente dentro de un bucle for-each. Esto conduce a errores y a comportamientos impredecibles. Solución: cree siempre una lista nueva para los resultados y rellénela.

Error n.º 2: conversiones de tipo incorrectas. Si trabaja con colecciones «raw» (por ejemplo, a través de Object) y convierte los elementos a un tipo incorrecto, obtendrá ClassCastException. Utilice genéricos (List<T>) y preste atención a las firmas.

Error n.º 3: uso ineficiente de recursos. Para colecciones muy grandes, la creación constante de nuevas listas y la copia de elementos puede notarse en memoria y tiempo. En la mayoría de tareas cotidianas es aceptable, pero al procesar grandes volúmenes de datos tenga en cuenta la complejidad y, si es necesario, optimice el enfoque.

1
Tarea
JAVA 25 SELF, nivel 28, lección 1
Bloqueada
Creación de la lista de estudiantes para el álbum de graduación 🎓
Creación de la lista de estudiantes para el álbum de graduación 🎓
1
Tarea
JAVA 25 SELF, nivel 28, lección 1
Bloqueada
Unir los tesoros de distintos cofres 💰
Unir los tesoros de distintos cofres 💰
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION