0Pricing
R Academy · Lección

keep(), discard() y filtrado de listas

Filtre elementos de listas mediante funciones predicado para crear pipelines limpios.

keep(), discard() y filtrado de listas es una lección gratuita de R Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de R Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de R Academy incluye 4 lecciones en total.

Filtrado de listas con purrr

purrr ofrece una familia de funciones para filtrar, buscar y comprobar listas según predicados. Un predicado es una función que devuelve TRUE o FALSE. Estas funciones sustituyen las llamadas extensas a Filter() y los bucles condicionales.

library(purrr)

# A mixed list to filter
mixed <- list(1L, 'hello', 3.14, NULL, TRUE, 42L, 'world', NULL)

cat('Total elements:', length(mixed), '\n')
cat('Non-NULL elements:', length(compact(mixed)))

keep() — Conservar los elementos que coinciden con un predicado

keep(.x, .p) conserva únicamente los elementos de .x para los que el predicado .p devuelve TRUE. Es lo contrario de discard(). El predicado puede ser un nombre de función, una fórmula o un vector lógico.

library(purrr)

mixed <- list(1L, 'hello', 3.14, TRUE, 42L, 'world', 2.7)

# Keep only numeric values
numeric_only <- keep(mixed, is.numeric)
print(numeric_only)

# Keep values greater than 5
keep(mixed, ~is.numeric(.x) && .x > 5)

discard() — Eliminar los elementos que coinciden con un predicado

discard(.x, .p) elimina los elementos cuyo predicado devuelve TRUE y conserva el resto. Es el complemento de keep(). Úselo para filtrar valores nulos, NAs o tipos no deseados de una lista.

library(purrr)

results <- list(
  model_a = list(rmse=2.5, converged=TRUE),
  model_b = list(rmse=NA, converged=FALSE),
  model_c = list(rmse=1.8, converged=TRUE),
  model_d = list(rmse=NA, converged=FALSE)
)

# Discard models that did not converge
converged_models <- discard(results, ~!.x$converged)
map_dbl(converged_models, ~.x$rmse)

compact() — Eliminar elementos NULL

compact(.x) elimina todos los elementos NULL de una lista; equivale a discard(.x, is.null), pero es más conciso. Resulta especialmente útil después de llamadas a map() que puedan devolver NULL para algunas entradas.

library(purrr)

# Simulate fetching data that might return NULL
ids <- 1:6
fetch_data <- function(id) {
  if (id %% 2 == 0) NULL else list(id=id, value=id*10)
}

raw_results <- map(ids, fetch_data)
cat('With NULLs:', length(raw_results), '\n')

clean_results <- compact(raw_results)
cat('Without NULLs:', length(clean_results))

detect() — Encontrar la primera coincidencia

detect(.x, .p) devuelve el primer elemento que satisface el predicado. Si ningún elemento coincide, devuelve NULL. Use detect(.right=TRUE) para buscar desde la derecha y encontrar la última coincidencia.

library(purrr)

prices <- list(15.99, 8.50, 23.99, 5.25, 19.99, 4.75)

# Find first price under $10
first_cheap <- detect(prices, ~.x < 10)
cat('First price under $10:', first_cheap, '\n')

# Find last price under $10
last_cheap <- detect(prices, ~.x < 10, .right=TRUE)
cat('Last price under $10:', last_cheap)

detect_index() — Encontrar la posición de la primera coincidencia

detect_index(.x, .p) devuelve el índice del primer elemento que satisface el predicado (o 0L si no encuentra ninguno). Es útil cuando necesita la posición y no el valor, por ejemplo, para actualizar o extraer ese elemento.

library(purrr)

models <- list(
  list(name='lm', rmse=3.5),
  list(name='rf', rmse=2.1),
  list(name='xgb', rmse=1.8),
  list(name='svm', rmse=2.4)
)

# Find the index of the best model (lowest RMSE)
best_idx <- detect_index(models, function(m) m$rmse < 2.0)
cat('Best model index:', best_idx, '\n')
cat('Best model name:', models[[best_idx]]$name)

every() — ¿Coinciden todos los elementos?

every(.x, .p) devuelve TRUE si el predicado se cumple para todos los elementos. Se detiene en el primer FALSE. Equivale a all(map_lgl(.x, .p)), pero se evalúa de forma diferida.

library(purrr)

batch_results <- list(
  list(status='success', rows=150),
  list(status='success', rows=200),
  list(status='success', rows=175)
)

failed_batch <- list(
  list(status='success', rows=150),
  list(status='error', rows=0),
  list(status='success', rows=175)
)

cat('All success (good):', every(batch_results, ~.x$status == 'success'), '\n')
cat('All success (bad):', every(failed_batch, ~.x$status == 'success'))

some() — ¿Coincide algún elemento?

some(.x, .p) devuelve TRUE si al menos un elemento satisface el predicado. Se detiene en el primer TRUE. Equivale a any(map_lgl(.x, .p)), pero se evalúa de forma diferida.

library(purrr)

datasets <- list(
  data.frame(x=1:3, y=c(1,NA,3)),
  data.frame(x=4:6, y=7:9),
  data.frame(x=7:9, y=c(NA,NA,NA))
)

# Does any dataset contain NAs?
cat('Any NAs:', some(datasets, anyNA), '\n')

# Is every dataset NA-free?
cat('All clean:', every(datasets, ~!anyNA(.x)))

none() — ¿No coincide ningún elemento?

none(.x, .p) devuelve TRUE si ningún elemento satisface el predicado. Equivale a !some(.x, .p), pero se lee con mayor claridad en contextos de validación en los que desea afirmar la ausencia de una condición.

library(purrr)

api_responses <- list(
  list(code=200, data='OK'),
  list(code=200, data='OK'),
  list(code=201, data='Created')
)

# Ensure no errors occurred
no_errors <- none(api_responses, ~.x$code >= 400)
cat('No errors:', no_errors, '\n')

# Check another batch
bad_batch <- c(api_responses, list(list(code=500, data='Error')))
none(bad_batch, ~.x$code >= 400)

Combinar keep() con map()

Encadenar keep() (o discard()) con map() es un patrón habitual: primero se filtra la lista para conservar los elementos relevantes y después se aplica una transformación. Así, la lógica de filtrado queda claramente separada de la lógica de procesamiento.

library(purrr)

model_results <- list(
  list(name='A', converged=TRUE, rmse=2.5),
  list(name='B', converged=FALSE, rmse=NA),
  list(name='C', converged=TRUE, rmse=1.8),
  list(name='D', converged=TRUE, rmse=3.1)
)

# Keep converged, extract RMSE
model_results %>%
  keep(~.x$converged) %>%
  map_dbl(~.x$rmse)

Usar keep() con funciones is.*

Las funciones predicado integradas de R (is.numeric, is.character, is.null, is.na, is.finite) funcionan directamente como predicados en keep() y discard(), sin necesidad de envolverlas en ~.

library(purrr)

mixed_env <- list(
  count = 42L,
  name = 'Alice',
  ratio = 3.14,
  flag = TRUE,
  missing = NULL,
  data = data.frame(x=1:3)
)

# Extract different types
numeric_items <- keep(mixed_env, is.numeric)
cat('Numeric items:', length(numeric_items), '\n')

# Remove NULL items
cleaned <- discard(mixed_env, is.null)
cat('After removing NULL:', length(cleaned))

Comprobación rápida

¿Qué devuelve detect(.x, .p) cuando ningún elemento de .x satisface el predicado .p?

Resumen: funciones para filtrar listas

Ideas clave sobre las herramientas de purrr para filtrar listas:

  • keep(.x, .p) — conserva los elementos cuyo predicado es TRUE
  • discard(.x, .p) — elimina los elementos cuyo predicado es TRUE
  • compact(.x) — elimina todos los elementos NULL
  • detect(.x, .p) — devuelve el primer elemento que coincide con el predicado (o NULL)
  • detect_index(.x, .p) — devuelve el índice de la primera coincidencia (o 0L)
  • every(.x, .p) — TRUE si todos los elementos coinciden
  • some(.x, .p) — TRUE si algún elemento coincide
  • none(.x, .p) — TRUE si ningún elemento coincide
library(purrr)

scores <- list(45, 72, 88, 53, 91, 67, 39, 85)

passing <- keep(scores, ~.x >= 60)
failing <- discard(scores, ~.x >= 60)

cat('Passing:', length(passing), 'students\n')
cat('Failing:', length(failing), 'students\n')
cat('All pass:', every(scores, ~.x >= 60), '\n')
cat('Any fail:', some(scores, ~.x < 60), '\n')
cat('First pass score:', detect(scores, ~.x >= 60))

Preguntas frecuentes

¿La lección «keep(), discard() y filtrado de listas» es gratis?

Sí — el texto completo de «keep(), discard() y filtrado de listas» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de R Academy, actualiza a CoddyKit PRO. El curso de R Academy incluye 4 lecciones en total.

¿Qué aprenderé en «keep(), discard() y filtrado de listas»?

Filtre elementos de listas mediante funciones predicado para crear pipelines limpios. Practicas R Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar R Academy?

No se requiere experiencia previa. R Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «keep(), discard() y filtrado de listas»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de R Academy?

Sí. Cada lección de R Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. map() y variantes tipadas
  2. map2() y pmap() para varias entradas
  3. reduce(), accumulate() y walk()
  4. keep(), discard() y filtrado de listas
← Volver a R Academy