keep(), discard() en lijstfiltering
Filter lijstelementen met predicaatfuncties voor overzichtelijke pipelines.
keep(), discard() en lijstfiltering is een gratis R Academy-les op CoddyKit. Dit is les 4 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject R Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus R Academy bevat in totaal 4 lessen.
Lijsten filteren met purrr
purrr biedt een reeks functies voor het filteren, doorzoeken en testen van lijsten op basis van predicaten. Een predicaat is een functie die TRUE of FALSE retourneert. Deze functies vervangen omslachtige aanroepen van Filter() en voorwaardelijke lussen.
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() — elementen behouden die aan een predicaat voldoen
keep(.x, .p) behoudt alleen de elementen van .x waarvoor het predicaat .p TRUE retourneert. Het is het tegenovergestelde van discard(). Het predicaat kan een functienaam, een formule of een logische vector zijn.
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() — elementen verwijderen die aan een predicaat voldoen
discard(.x, .p) verwijdert elementen waarvoor het predicaat TRUE retourneert en behoudt de rest. Het is het spiegelbeeld van keep(). Gebruik het om nullen, NA-waarden of ongewenste typen uit een lijst te filteren.
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() — NULL-elementen verwijderen
compact(.x) verwijdert alle NULL-elementen uit een lijst. Dit is gelijk aan discard(.x, is.null), maar beknopter. Het is vooral handig na map()-aanroepen die voor sommige invoerwaarden NULL kunnen retourneren.
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() — eerste overeenkomst vinden
detect(.x, .p) retourneert het eerste element dat aan het predicaat voldoet. Als geen enkel element overeenkomt, retourneert de functie NULL. Gebruik detect(.right=TRUE) om vanaf rechts te zoeken en de laatste overeenkomst te vinden.
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() — positie van eerste overeenkomst vinden
detect_index(.x, .p) retourneert de index van het eerste element dat aan het predicaat voldoet (of 0L als niets wordt gevonden). Dit is handig wanneer je de positie nodig hebt in plaats van de waarde, bijvoorbeeld om dat element bij te werken of eruit te halen.
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() — voldoen alle elementen?
every(.x, .p) retourneert TRUE als aan het predicaat wordt voldaan voor elk element. De functie stopt bij de eerste FALSE. Dit is gelijk aan all(map_lgl(.x, .p)), maar met luie evaluatie.
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() — voldoet een element?
some(.x, .p) retourneert TRUE als ten minste één element aan het predicaat voldoet. De functie stopt bij de eerste TRUE. Dit is gelijk aan any(map_lgl(.x, .p)), maar met luie evaluatie.
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() — voldoet geen enkel element?
none(.x, .p) retourneert TRUE als geen enkel element aan het predicaat voldoet. Dit is gelijk aan !some(.x, .p), maar leest duidelijker in validatiecontexten waarin je de afwezigheid van een voorwaarde wilt bevestigen.
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)keep() combineren met map()
Het aan elkaar koppelen van keep() (of discard()) met map() is een veelgebruikt patroon: filter eerst de lijst op relevante elementen en pas daarna een transformatie toe. Zo houd je de filterlogica en de verwerkingslogica netjes gescheiden.
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)keep() gebruiken met is.*-functies
De ingebouwde predicaatfuncties van R, is.* (is.numeric, is.character, is.null, is.na, is.finite), werken rechtstreeks als predicaten in keep() en discard(), zonder dat je ze in ~ hoeft te verpakken.
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))Korte controle
Wat geeft detect(.x, .p) terug als geen enkel element in .x aan predicaat .p voldoet?
Samenvatting: functies voor het filteren van lijsten
Belangrijkste punten over de hulpmiddelen van purrr voor het filteren van lijsten:
keep(.x, .p)— behoudt elementen waarvoor het predicaat TRUE isdiscard(.x, .p)— verwijdert elementen waarvoor het predicaat TRUE iscompact(.x)— verwijdert alle NULL-elementendetect(.x, .p)— geeft het eerste element terug dat aan het predicaat voldoet (of NULL)detect_index(.x, .p)— geeft de index van de eerste overeenkomst terug (of 0L)every(.x, .p)— TRUE als alle elementen overeenkomensome(.x, .p)— TRUE als minstens één element overeenkomtnone(.x, .p)— TRUE als geen enkel element overeenkomt
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))Leer R met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 43
- Lessen
- 159
Veelgestelde vragen
Is de les “keep(), discard() en lijstfiltering” gratis?
Ja — je kunt hier op het web alle 3 lessen van het leerpad R Academy, waaronder “keep(), discard() en lijstfiltering”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus R Academy bevat in totaal 4 lessen.
Wat leer ik in “keep(), discard() en lijstfiltering”?
Filter lijstelementen met predicaatfuncties voor overzichtelijke pipelines. Je oefent met R Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met R Academy te beginnen?
Ervaring vooraf is niet nodig. R Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 4 van 4.
Hoe lang duurt de les “keep(), discard() en lijstfiltering”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over R Academy?
Ja. Elke les over R Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- map() en getypeerde varianten
- map2() en pmap() voor meerdere invoerwaarden
- reduce(), accumulate() en walk()
- keep(), discard() en lijstfiltering