Skip to main content

Command Palette

Search for a command to run...

Colecciones, transformaciones y recursión en Clojure

Updated
5 min readView as Markdown
Colecciones, transformaciones y recursión en Clojure

En esta segunda semana de Clojure, dejamos atrás la parte más introductoria y entramos a una de las ideas más importantes del lenguaje: trabajar con colecciones de forma funcional.

Cuando empezamos a construir software real, casi todo gira alrededor de recibir datos, transformarlos, filtrarlos y combinarlos para obtener respuestas útiles. En Clojure, esto se hace con una gran claridad gracias a funciones como map, filter, reduce y a la forma natural de manipular maps, vectors, lists y sets.

Source Code: https://github.com/joedayz/clojure-senior-path/tree/week2

1) Las colecciones son el corazón de Clojure

Clojure está muy centrado en el trabajo con datos estructurados. Las colecciones más comunes son:

(def nums [1 2 3 4 5])
(def fruits '(:manzana :pera :uva))
(def user {:name "Ana" :age 30})
(def tags #{:backend :clojure :functional})

Cada una tiene un propósito diferente:

  • Vector: [...] → colección ordenada

  • Lista: '(...) → estructura común en programación funcional

  • Map: {...} → pares clave/valor

  • Set: #{...} → valores únicos

Esto es importante porque en proyectos reales no solo guardamos valores sueltos; normalmente trabajamos con listas de productos, usuarios, pedidos, métricas, clientes y estados.

2) Transformar datos con map

La función map aplica una operación a cada elemento de una colección.

(defn double-all
  [numbers]
  (map #(* 2 %) numbers))

Uso:

(double-all [1 2 3 4])
;; => (2 4 6 8)

Esto parece pequeño, pero es extremadamente útil. En aplicaciones reales, map te permite:

  • duplicar precios

  • convertir cadenas a mayúsculas

  • calcular impuestos

  • agregar metadata a cada registro

  • aplicar transformaciones a listas completas

La belleza de map es que expresa claramente: “aplica esta operación a cada elemento”.

3) Filtrar con filter

Cuando queremos quedarnos con los elementos que cumplen una condición, usamos filter.

(defn even-only  [numbers]
  (filter even? numbers))

Uso:

(even-only [123456])
;; => (2 4 6)

Este patrón es muy común en negocios y aplicaciones:

  • clientes activos

  • pedidos mayores a cierto monto

  • productos con precio superior a un umbral

  • usuarios con rol específico

filter no solo simplifica el código; también hace que el propósito sea más fácil de leer.

4) Reducir datos con reduce

reduce toma una colección y la combina en un solo valor. Es ideal para sumar, acumular, agrupar o construir resultados finales.

(defn sum-numbers  [numbers]
  (reduce +0 numbers))

Uso:

(sum-numbers [12345])
;; => 15

En proyectos reales, reduce se usa para:

  • sumar ventas

  • calcular totales

  • crear resúmenes por cliente

  • acumular contadores

  • generar reportes

Por ejemplo:

(defn total-sales  [orders]
  (reduce+ (map:totalorders)))

Aquí primero transformamos cada pedido a su total con map, y luego reducimos esa colección con +.

5) Trabajar con maps y datos de negocio

Los maps son probablemente la estructura más importante cuando modelamos información del negocio. Los usuarios, productos, pedidos y clientes se representan muy bien como maps.

(defn describe-user  [{:keys [nameageemail]}]
  (strname" tiene "age" años y su email es "email))

Uso:

(describe-user {:name"Ana":age30:email"ana@example.com"})
;; => "Ana tiene 30 años y su email es ana@example.com"

Con esto vemos algo muy útil: no escribimos mucho código para acceder a los datos, y el programa se vuelve mucho más legible.

También es común filtrar registros por una propiedad:

(defn active-users  [users]
  (filter:activeusers))

Cuando representas entidades como maps, te resulta mucho más fácil crear lógica de negocio clara y expresiva.

6) Recursión y cómo pensar en flujo de datos

Aunque Clojure ofrece herramientas muy poderosas para iterar, la recursión sigue siendo una pieza clave para entender cómo funciona la lógica funcional.

(defnsum-recursive  [numbers]
  (if (empty?numbers)
0    (+ (firstnumbers)
       (sum-recursive (restnumbers)))))

La idea es simple:

  1. revisamos el primer elemento

  2. tomamos el resto de la colección

  3. repetimos hasta llegar al caso base

Cuando la colección está vacía, la recursión termina.

Este tipo de ejemplo ayuda a internalizar la forma en que Clojure trata los datos: como flujo que se va consumiendo paso a paso, sin depender tanto de un estado mutable.

7) Pipelines de transformación

Una de las cosas más valiosas en Clojure es saber encadenar funciones para formar un pipeline claro.

(defnexpensive-items  [products]
  (->>products       (filter #(> (:price%) 100))
       (map:name)))

Esto significa:

  1. tomar la colección de productos

  2. filtrar solo los caros

  3. mapear solo sus nombres

Eso es exactamente la mentalidad de Clojure: describir el flujo del dato de una manera muy legible y muy expresiva.

8) Por qué esta semana importa tanto

La semana 2 no trata solo de aprender funciones aisladas. Se trata de desarrollar una manera de pensar:

  • qué datos tengo

  • qué quiero transformar

  • qué condición necesito aplicar

  • qué resultado final necesito obtener

Esto es lo que hace que Clojure sea tan potente en proyectos reales.

Cuando entiendes map, filter y reduce, ya puedes:

  • sumar ventas

  • filtrar clientes activos

  • calcular promociones

  • generar reportes

  • transformar data de una API

  • normalizar información

  • preparar estructuras que luego usen otras partes del sistema

9) El siguiente paso

Esta semana nos pone en un nivel mucho más útil para el desarrollo real. Ya no solo estamos escribiendo funciones pequeñas; estamos manipulando datos con intención y claridad.

La clave es que cada una de estas herramientas no se usa de forma aislada. Se combinan. Se encadenan. Y eso es lo que hace que el código en Clojure sea tan elegante.

En la siguiente etapa, seguiremos avanzando hacia la organización de proyectos, pruebas y modelado de dominio, pero la base que aprendimos en esta semana será esencial para todo lo que venga después.

Si ya estás practicando con map, filter, reduce y recursión, entonces ya estás empezando a pensar como desarrollador funcional. Y esa es la parte más valiosa del aprendizaje.

Enjoy!

Joe