0Pricing
R Academy · Lekcja

keep(), discard() i filtrowanie list

Filtruj elementy list za pomocą funkcji predykatów, aby tworzyć przejrzyste potoki.

keep(), discard() i filtrowanie list to bezpłatna lekcja R Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej R Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs R Academy zawiera 4 lekcji w sumie.

Filtrowanie list za pomocą purrr

purrr udostępnia zestaw funkcji do filtrowania, wyszukiwania i testowania list na podstawie predykatów. Predykat to funkcja zwracająca TRUE lub FALSE. Funkcje te zastępują rozbudowane wywołania Filter() i pętle warunkowe.

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() — zachowywanie elementów spełniających predykat

keep(.x, .p) zachowuje tylko te elementy .x, dla których predykat .p zwraca TRUE. Jest przeciwieństwem discard(). Predykatem może być nazwa funkcji, formuła lub wektor logiczny.

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() — usuwanie elementów spełniających predykat

discard(.x, .p) usuwa elementy, dla których predykat zwraca TRUE, a pozostałe zachowuje. Jest lustrzanym odpowiednikiem keep(). Należy użyć go do odfiltrowania wartości null, wartości NA lub niepożądanych typów z listy.

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() — usuwanie elementów NULL

compact(.x) usuwa wszystkie elementy NULL z listy — jest równoważne discard(.x, is.null), ale bardziej zwięzłe. Jest szczególnie przydatne po wywołaniach map(), które dla niektórych danych wejściowych mogą zwracać NULL.

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() — znajdowanie pierwszego dopasowania

detect(.x, .p) zwraca pierwszy element spełniający predykat. Jeśli żaden element nie pasuje, zwraca NULL. Użyj detect(.right=TRUE), aby wyszukiwać od prawej strony i znaleźć ostatnie dopasowanie.

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() — znajdowanie pozycji pierwszego dopasowania

detect_index(.x, .p) zwraca indeks pierwszego elementu spełniającego predykat (lub 0L, jeśli nie znaleziono żadnego). Jest przydatne, gdy potrzebna jest pozycja, a nie wartość — na przykład do zaktualizowania lub wyodrębnienia tego elementu.

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() — czy wszystkie elementy pasują?

every(.x, .p) zwraca TRUE, jeśli predykat jest spełniony dla każdego elementu. Kończy działanie przy pierwszym FALSE. Jest równoważne all(map_lgl(.x, .p)), ale wykorzystuje ewaluację leniwą.

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() — czy pasuje dowolny element?

some(.x, .p) zwraca TRUE, jeśli predykat spełnia co najmniej jeden element. Kończy działanie przy pierwszym TRUE. Jest równoważne any(map_lgl(.x, .p)), ale wykorzystuje ewaluację leniwą.

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() — czy nie pasuje żaden element?

none(.x, .p) zwraca TRUE, jeśli predykatu nie spełnia żaden element. Jest równoważne !some(.x, .p), ale w kontekście walidacji, gdy trzeba potwierdzić brak danego warunku, jest czytelniejsze.

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)

Łączenie keep() z map()

Łączenie keep() (lub discard()) z map() to często stosowany wzorzec: najpierw filtruje Pan/Pani listę, aby pozostawić istotne elementy, a następnie stosuje transformację. Dzięki temu logika filtrowania jest wyraźnie oddzielona od logiki przetwarzania.

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)

Używanie keep() z funkcjami is.*

Wbudowane funkcje predykatowe R is.* (is.numeric, is.character, is.null, is.na, is.finite) działają bezpośrednio jako predykaty w keep() i discard(), bez konieczności opakowywania ich w ~.

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

Szybkie sprawdzenie

Co zwraca detect(.x, .p), gdy żaden element .x nie spełnia predykatu .p?

Podsumowanie: funkcje filtrowania list

Najważniejsze informacje o narzędziach pakietu purrr do filtrowania list:

  • keep(.x, .p) — zachowuje elementy, dla których predykat ma wartość TRUE
  • discard(.x, .p) — usuwa elementy, dla których predykat ma wartość TRUE
  • compact(.x) — usuwa wszystkie elementy NULL
  • detect(.x, .p) — zwraca pierwszy element spełniający predykat (lub NULL)
  • detect_index(.x, .p) — zwraca indeks pierwszego dopasowania (lub 0L)
  • every(.x, .p) — TRUE, jeśli wszystkie elementy spełniają predykat
  • some(.x, .p) — TRUE, jeśli dowolny element spełnia predykat
  • none(.x, .p) — TRUE, jeśli żaden element nie spełnia predykatu
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))

Często zadawane pytania

Czy lekcja „keep(), discard() i filtrowanie list” jest bezpłatna?

Tak — pełny tekst „keep(), discard() i filtrowanie list” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu R Academy, przejdź na CoddyKit PRO. Kurs R Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „keep(), discard() i filtrowanie list”?

Filtruj elementy list za pomocą funkcji predykatów, aby tworzyć przejrzyste potoki. Ćwiczysz R Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć R Academy?

Nie wymagamy żadnego doświadczenia. R Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „keep(), discard() i filtrowanie list”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji R Academy?

Tak. Każda lekcja R Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. map() i warianty typowane
  2. map2() i pmap() dla wielu danych wejściowych
  3. reduce(), accumulate() i walk()
  4. keep(), discard() i filtrowanie list
← Powrót do R Academy