0Pricing
R Academy · Lezione

keep(), discard() e filtraggio delle liste

Filtri gli elementi delle liste con funzioni predicato per ottenere pipeline pulite.

keep(), discard() e filtraggio delle liste è una lezione R Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento R Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso R Academy include 4 lezioni in totale.

Filtrare le liste con purrr

purrr offre una famiglia di funzioni per filtrare, cercare e verificare le liste in base a predicati. Un predicato è una funzione che restituisce TRUE o FALSE. Queste funzioni sostituiscono le chiamate prolisse a Filter() e i cicli condizionali.

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() — Conservare gli elementi che soddisfano un predicato

keep(.x, .p) conserva solo gli elementi di .x per i quali il predicato .p restituisce TRUE. È l'opposto di discard(). Il predicato può essere il nome di una funzione, una formula o un vettore logico.

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() — Rimuovere gli elementi che soddisfano un predicato

discard(.x, .p) rimuove gli elementi per i quali il predicato restituisce TRUE, conservando gli altri. È il complemento di keep(). Lo utilizzi per filtrare da una lista i valori nulli, gli NA o i tipi indesiderati.

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() — Rimuovere gli elementi NULL

compact(.x) rimuove tutti gli elementi NULL da una lista: equivale a discard(.x, is.null), ma è più conciso. È particolarmente utile dopo chiamate a map() che potrebbero restituire NULL per alcuni input.

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() — Trovare la prima corrispondenza

detect(.x, .p) restituisce il primo elemento che soddisfa il predicato. Se nessun elemento corrisponde, restituisce NULL. Utilizzi detect(.right=TRUE) per cercare da destra e trovare l'ultima corrispondenza.

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() — Trovare la posizione della prima corrispondenza

detect_index(.x, .p) restituisce l'indice del primo elemento che soddisfa il predicato, oppure 0L se non ne trova nessuno. È utile quando serve la posizione anziché il valore, ad esempio per aggiornare o estrarre quell'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() — Tutti gli elementi corrispondono?

every(.x, .p) restituisce TRUE se il predicato è soddisfatto per ogni elemento. Interrompe la valutazione al primo FALSE. Equivale a all(map_lgl(.x, .p)), ma con valutazione lazy.

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() — Almeno un elemento corrisponde?

some(.x, .p) restituisce TRUE se almeno un elemento soddisfa il predicato. Interrompe la valutazione al primo TRUE. Equivale a any(map_lgl(.x, .p)), ma con valutazione lazy.

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() — Nessun elemento corrisponde?

none(.x, .p) restituisce TRUE se nessun elemento soddisfa il predicato. Equivale a !some(.x, .p), ma risulta più chiaro nei contesti di convalida in cui si vuole verificare l'assenza di una condizione.

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)

Combinare keep() con map()

Concatenare keep() (o discard()) con map() è uno schema comune: prima si filtra la lista per conservare gli elementi pertinenti, poi si applica una trasformazione. In questo modo la logica di filtraggio e quella di elaborazione restano chiaramente separate.

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)

Usare keep() con le funzioni is.*

Le funzioni predicato integrate di R is.* (is.numeric, is.character, is.null, is.na, is.finite) possono essere usate direttamente come predicati in keep() e discard(), senza doverle racchiudere in ~.

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))

Verifica rapida

Che cosa restituisce detect(.x, .p) quando nessun elemento di .x soddisfa il predicato .p?

Riepilogo: funzioni per filtrare le liste

Punti chiave degli strumenti di purrr per filtrare le liste:

  • keep(.x, .p) — conserva gli elementi per cui il predicato è TRUE
  • discard(.x, .p) — rimuove gli elementi per cui il predicato è TRUE
  • compact(.x) — rimuove tutti gli elementi NULL
  • detect(.x, .p) — restituisce il primo elemento che soddisfa il predicato (oppure NULL)
  • detect_index(.x, .p) — restituisce l'indice della prima corrispondenza (oppure 0L)
  • every(.x, .p) — TRUE se tutti gli elementi soddisfano il predicato
  • some(.x, .p) — TRUE se almeno un elemento soddisfa il predicato
  • none(.x, .p) — TRUE se nessun elemento soddisfa il predicato
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))

Domande Frequenti

La lezione «keep(), discard() e filtraggio delle liste» è gratuita?

Sì — il testo completo di «keep(), discard() e filtraggio delle liste» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso R Academy, passa a CoddyKit PRO. Il corso R Academy include 4 lezioni in totale.

Cosa imparerò in «keep(), discard() e filtraggio delle liste»?

Filtri gli elementi delle liste con funzioni predicato per ottenere pipeline pulite. Eserciti R Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare R Academy?

Non è richiesta alcuna esperienza precedente. R Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «keep(), discard() e filtraggio delle liste»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione R Academy?

Sì. Ogni lezione R Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. map() e varianti tipizzate
  2. map2() e pmap() per input multipli
  3. reduce(), accumulate() e walk()
  4. keep(), discard() e filtraggio delle liste
← Torna a R Academy