How do I extract values from uniform list in R?
For example, how do I get a vector of each and every person's age in the list people
below:
> people = vector("list", 5)
> people[[1]] = c(name="Paul", age=23)
> people[[2]] = c(name="Peter", age=35)
> people[[3]] = c(name="Sam", age=20)
> people[[4]] = c(name="Lyle", age=31)
> people[[5]] = c(name="Fred", age=26)
> ag开发者_开发问答es = ???
> ages
[1] 23 35 20 31 26
Is there an equivalent of a Python list comprehension or something to the same effect?
You can use sapply:
> sapply(people, function(x){as.numeric(x[2])})
[1] 23 35 20 31 26
Given the data structure you provided, I would use sapply
:
sapply(people, function(x) x[2])
> sapply(people, function(x) x[2])
age age age age age
"23" "35" "20" "31" "26"
However, you'll notice that the results of this are character data.
> class(people[[1]])
[1] "character"
One approach would be to coerce to as.numeric()
or as.integer()
in the call to sapply.
Alternatively - if you have flexibility over how you store the data in the first place, it may make sense to store it as a list of data.frame
s:
people = vector("list", 5)
people[[1]] = data.frame(name="Paul", age=23)
people[[2]] = data.frame(name="Peter", age=35)
...
If you are going to go that far, you may also want to consider a single data.frame for all of your data:
people2 <- data.frame(name = c("Paul", "Peter", "Sam", "Lyle", "Fred")
, age = c(23,35,20,31, 26))
There may be some other reason why you didn't consider this approach the first time around though...
ages <- sapply(1:length(people), function(i) as.numeric(people[[i]][[2]]))
ages
Output:
[1] 23 35 20 31 26
Though this question is pretty old, I'd like to share my approach to this. It is certainly possible to do with the sapply
as
tflutre suggested. But I find it more intuitive by using the unlist
function:
> ages <- unlist(people, use.names = F)[seq(2, 2 * length(people), 2)]
> ages
[1] "23" "35" "20" "31" "26"
NOTE the multiplication by two in
2 * length(people)
, there are two elements stored in thepoeple
list. This can be made more generic by writinglength(people[[1]]) * length(people)
Here unlist(people, use.names = F)
yields
[1] "Paul" "23" "Peter" "35" "Sam" "20" "Lyle" "31" "Fred"
[10] "26"
and we slice that by every other element using seq
command.
Alternatively to the apply
-family there's @Hadley's purrr
package which offers the map_
-functions for this kind of job.
(There's a few differences to the apply
-family discussed for example here.)
OPs example:
people = vector("list", 5)
people[[1]] = c(name="Paul", age=23)
people[[2]] = c(name="Peter", age=35)
people[[3]] = c(name="Sam", age=20)
people[[4]] = c(name="Lyle", age=31)
people[[5]] = c(name="Fred", age=26)
The sapply
approach:
ages_sapply <- sapply(people, function(x){as.numeric(x[2])})
print(ages_sapply)
[1] 23 35 20 31 26
And the map
approach:
ages_map <- purrr::map_dbl(people, function(x){as.numeric(x[2])})
print(ages_map)
[1] 23 35 20 31 26
Of course they are identical:
identical(ages_sapply, ages_map)
[1] TRUE
精彩评论