Reputation: 1381
I want to construct an object list and extract objects based on one of their attributes. For example
persons_list <- list(PersonA = list(color = 'red', group = 1),
PersonsB = list(color = 'blue', group = 1),
PersonsC = list(color = 'green', group = 2))
Now I want to extract all colors as a vector where group is equal to 1 such that the result is:
c('red', 'blue')
I'm not sure if a list is the way to go here, but I chose it because I also want to be able to use the autocomplete/browse function of a list by typing
persons_list$PersonA
Upvotes: 1
Views: 4652
Reputation: 1011
I know this is old but I missed the more general answer.
I would use:
unlist(lapply(persons_list[which(sapply(persons_list, function(person) { person$group==1 }))], function(x) x$color), use.name = FALSE)
Or for easier reading, I'd probably split it into two lines:
First filter:
persons_in_group_1 = persons_list[which(sapply(persons_list, function(person) { person$group==1 }))]
then map the desired property:
unlist(lapply(persons_in_group_1, function(x) x$color ), use.names = FALSE)
Upvotes: 0
Reputation: 2539
Akrun is always faster. :-)
More generally. You can build some general function to do this job without too much cognitive effort. I haven't build any tool to select things from list yet. But I can drop things with
remove_if <- function(lst,test_fn) {
## DD . char or list
if (class(lst)=="character"){
unlist(lapply(lst ,function(x){if(!(test_fn(x))) x }))
} else {
remove_if_null(lapply(lst ,function(x){if(!(test_fn(x))) x }))}
}
It removes group 2 then select the part you need.
unlist(lapply(remove_if(persons_list, function(x) x$group==2),"[[",1))
## PersonA PersonsB
## "red" "blue"
Upvotes: 2
Reputation: 10671
library(rlist)
has bunch of nice list focused functions to bring some of the tidy verbs to list operations.
library(rlist)
library(magrittr)
list.filter(persons_list, group == 1) %>%
list.select(color) %>%
unlist(use.names = F)
Upvotes: 1
Reputation: 132706
No, that data structure is suboptimal for your use-case. Use a data.frame:
persons <- data.frame(person = c("A", "B", "C"),
color = c("red", "blue", "green"),
group = c(1, 1, 2),
stringsAsFactors = FALSE)
persons[persons$group == 1, "color"]
#[1] "red" "blue"
Not only is a tabular structure more natural, lookup is also more efficient.
Upvotes: 1
Reputation: 887118
We can do
unlist(lapply(persons_list, function(x) x$color[x$group==1]), use.names = FALSE)
#[1] "red" "blue"
Upvotes: 2