[R] How to extract sublist from a list?

Joshua Wiley jwiley.psych at gmail.com
Sun Aug 7 17:15:51 CEST 2011


Hi Richard,

Sorry for the delay, I had stopped tracking this conversation (the
more interesting question, though is what was I searching for in my
gmail archives that lead me to see this and notice your followup
email...).  Anyway, Michael is correct about what is going on.  One
aspect that might not be clear from reading the documentation is how:

lapply(X = lst, FUN = `[[`, "y")

manages to pass what it should where.  In particular, after reading
?lapply you may be thinking, "Okay, so lapply passes each element of
the X argument, as the first argument of the function called, and then
anything after the FUN argument is passed on via ... to the function
named in the FUN argument (that's a mouthful, sorry).

lst <- list(sub1 = list(x = "a", y = "ab"),
  sub2 = list(x = "c", y = "ad"))

lapply is basically doing:

lst[[1]][["y"]]
lst[[2]][["y"]]

but it puts them in a list and retains the names.  But that looks like
"y" is the first argument.  What's going on?  Operators (such as the
extraction operators `[[`) can behave in a special way where their
first argument is on the left.  However, the following also works:

`[[`(lst[[1]], "y")
`[[`(lst[[2]], "y")

written that way, it is easier to see that `[[` is a regular function
too, and how the data can be passed tot he first argument, and "y" to
the second.  Using a different extraction operator, you can see that
result:

`[`(lst[[2]], "y")

*apply just loops through each element of lst.  In addition to the
documentation, you can also just type:

sapply

at your console (no parentheses), and see the function definition.
There you see it actually calls lapply(), it just simplifies the
output if possible (and asked to, which it is by default).  Just a
quick note about that, you can set simplify = FALSE and USE.NAMES =
FALSE, but to do this, you would need to *explicitly name the
arguments* because they come *after* ... which is greedy and will grab
any unnamed TRUEs/FALSEs to pass on to FUN.  This can even have at
first glance strange consequences:

> sapply(lst, `[[`, "y", FALSE, FALSE)
Error in FUN(X[[1L]], ...) : incorrect number of subscripts

and error results because too many arguments were passed to `[[`

## looks like the results of lapply() now
> sapply(lst, `[[`, "y", simplify = FALSE, USE.NAMES = FALSE)
$sub1
[1] "ab"

$sub2
[1] "ad"


Cheers,

Josh

On Thu, Aug 4, 2011 at 6:30 AM, R. Michael Weylandt
<michael.weylandt at gmail.com> <michael.weylandt at gmail.com> wrote:
> I'm not Josh Wiley, but I think I can answer this:
>
> When dealing with lists, its often more convenient to use "[[" instead of
> "[" because "[" returns a single element list while "[[" returns the list
> element itself. (i.e., if I set x = list(Q = rnorm(64), V =
> matrix(rnorm(64),8)) then x["Q"] is a list that has one element which is a
> vector while x[["Q"]] is just that vector). With this in mind, we can parse
> Josh's code:
>
> lapply goes through each element of the list given in the first argument and
> applies the function in the second argument with the third argument as any
> necessary argument for the function (that's not totally clear, but I don't
> really know how to state it more directly). So for your case,
>
> lapply(list, "[[","y") looks at each element of list: sub1, sub2, sub3, etc.
> and does the following: [["y"]]-- thus it returns exactly, list$sub1$y,
> list$sub2$y, list$sub3$y as desired. Or more precisely, list$sub1[["y"]],
> etc. which is effectively the same thing -- see Josh's original post for
> details on the subtle differences.
>
> sapply is just a version of lapply that plays a little nicer. For example,
> with x as above: lapply(x,mean) gives me a list of two elements which are
> the means, while sapply(x,mean) gives me a vector of the same information.
> Sometimes it's a little nicer.
>
> Hopefully this helps, but for more information, try these:
>
> ? lapply
> ? "[["
>
> at  your command prompt.
>
> Michael Weylandt
>
> On Thu, Aug 4, 2011 at 6:57 AM, Richard Ma <xuanlong.ma at uts.edu.au> wrote:
>
>> Hi Joshua,
>>
>> Really helpful that you posted so many useful solutions for my problem.
>>
>> I can understand all your codes except these:
>>
>> *[code]
>> lapply(lst, `[[`, "y")
>> ## or if you are only retrieving a single value
>> sapply(lst, `[[`, "y")
>> [/code]*
>>
>> Can you explain these a little bit? What does '[[' means?
>>
>> Thanks a lot,
>> Richard
>>
>>
>> Joshua Wiley-2 wrote:
>> >
>> > On Thu, Aug 4, 2011 at 12:12 AM, Ashim Kapoor
>> > <ashimkapoor at gmail.com> wrote:
>> >>> How would we do this problem looping over seq(1:2) ?
>> >
>> > Because this goes to an email list serv, it is good practice to quote
>> > the original problem.  I have no idea what "this" is.
>> >
>> >>>
>> >>>
>> >> To extend the example in the corresponding nabble post : -
>> >>  sub1<-list(x="a",y="ab")
>> >>  sub2<-list(x="c",y="ad")
>> >>  lst<-list(sub1=sub1,sub2=sub2)
>> >>  for ( t in seq(1:2) )  print(lst[[t]]$y)
>> >>
>> >> So I can print out the sub1$y/sub2$y but it's not clear how to extract
>> >> them.
>> >
>> > Well, to extract them, just drop the call to print. You could use them
>> > directly in the loop or could store them in new variables.
>> >
>> > ## note seq(1:2) is redundant with simply 1:2
>> > or (t in 1:2) print(nchar(lst[[t]]$y))
>> >
>> > I am guess, though, that what you might be hoping to do is extract
>> > specific elements from a list and store the extract elements in a new
>> > list.
>> >
>> > lapply(1:2, function(i) lst[[i]]["y"])
>> > ## or compare
>> > lapply(1:2, function(i) lst[[i]][["y"]])
>> >
>> >>
>> >> My original was different though.
>> >>
>> >> How would  say:-
>> >>
>> >> for ( t in seq(1:2) ) sub"t"$y
>> >>
>> >> Where sub"t" evaluates to sub1 or sub 2?
>> >
>> > if you actually want "sub1", or "sub2":
>> >
>> > ## note that I am wrapping in print() not so that it works
>> > ## but so that you can see it at the console
>> > for (t in 1:2) print(paste("sub", t, sep = ''))
>> >
>> > from which we can surmise that the following should work:
>> >
>> > for (t in 1:2) print(lst[[paste("sub", t, sep = '')]])
>> >
>> > which trivially extends to:
>> >
>> > for (t in 1:2) print(lst[[paste("sub", t, sep = '')]]$y)
>> >
>> > or perhaps more appropriately
>> >
>> > for (t in 1:2) print(lst[[paste("sub", t, sep = '')]][["y"]])
>> >
>> > If you just need to go one level down for *all* elements of your list
>> >
>> > lapply(lst, `[[`, "y")
>> > ## or if you are only retrieving a single value
>> > sapply(lst, `[[`, "y")
>> >
>> > Hope this helps,
>> >
>> > Josh
>> >
>> >>
>> >> Many thanks.
>> >> Ashim
>> >>
>> >>
>> >>> On Thu, Aug 4, 2011 at 10:59 AM, Richard Ma
>> >>> <xuanlong.ma at uts.edu.au>wrote:
>> >>>
>> >>>> Thank you so much GlenB!
>> >>>>
>> >>>> I got it done using your method.
>> >>>>
>> >>>> I'm just curious how did you get this idea? Cause for me, this looks
>> so
>> >>>> tricky....
>> >>>>
>> >>>> Cheers,
>> >>>> Richard
>> >>>>
>> >>>> -----
>> >>>> I'm a PhD student interested in Remote Sensing and R Programming.
>> >>>> --
>> >>>> View this message in context:
>> >>>>
>> http://r.789695.n4.nabble.com/How-to-extract-sublist-from-a-list-tp3717451p3717713.html
>> >>>> Sent from the R help mailing list archive at Nabble.com.
>> >>>>
>> >>>> ______________________________________________
>> >>>> R-help at r-project.org mailing list
>> >>>> https://stat.ethz.ch/mailman/listinfo/r-help
>> >>>> PLEASE do read the posting guide
>> >>>> http://www.R-project.org/posting-guide.html
>> >>>> and provide commented, minimal, self-contained, reproducible code.
>> >>>>
>> >>>
>> >>>
>> >>
>> >>        [[alternative HTML version deleted]]
>> >>
>> >> ______________________________________________
>> >> R-help at r-project.org mailing list
>> >> https://stat.ethz.ch/mailman/listinfo/r-help
>> >> PLEASE do read the posting guide
>> >> http://www.R-project.org/posting-guide.html
>> >> and provide commented, minimal, self-contained, reproducible code.
>> >>
>> >
>> >
>> >
>> > --
>> > Joshua Wiley
>> > Ph.D. Student, Health Psychology
>> > Programmer Analyst II, ATS Statistical Consulting Group
>> > University of California, Los Angeles
>> > https://joshuawiley.com/
>> >
>> > ______________________________________________
>> > R-help at r-project.org mailing list
>> > https://stat.ethz.ch/mailman/listinfo/r-help
>> > PLEASE do read the posting guide
>> > http://www.R-project.org/posting-guide.html
>> > and provide commented, minimal, self-contained, reproducible code.
>> >
>>
>>
>> -----
>> I'm a PhD student interested in Remote Sensing and R Programming.
>> --
>> View this message in context:
>> http://r.789695.n4.nabble.com/How-to-extract-sublist-from-a-list-tp3717451p3718282.html
>> Sent from the R help mailing list archive at Nabble.com.
>>
>> ______________________________________________
>> R-help at r-project.org mailing list
>> https://stat.ethz.ch/mailman/listinfo/r-help
>> PLEASE do read the posting guide
>> http://www.R-project.org/posting-guide.html
>> and provide commented, minimal, self-contained, reproducible code.
>>
>
>        [[alternative HTML version deleted]]
>
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.
>



-- 
Joshua Wiley
Ph.D. Student, Health Psychology
Programmer Analyst II, ATS Statistical Consulting Group
University of California, Los Angeles
https://joshuawiley.com/



More information about the R-help mailing list