Defining names of list elements - r

Let's consider vector of names for the elements of my list:
name_vec <- c("name", "of", "the", "list", "elements")
This vector contains names of the elements of the list. Let's define an empty list and name each element with elements from name_vec
my_list <- list()
for (i in seq_len(length(name_vec))) {
my_list[[name_vec[i]]] <- i+1
}
However I find this solution highly inefficient due to fact that loop was used. I think that has to be some way to avoid it but I'm not aware of it. Tried to do something with lapply but it lead's me to nothing. Do you have any ideas how it can be done ?

One option could be:
as.list(setNames(seq_along(name_vec) + 1, name_vec))
$name
[1] 2
$of
[1] 3
$the
[1] 4
$list
[1] 5
$elements
[1] 6
The results are the same:
identical(my_list, as.list(setNames(seq_along(name_vec) + 1, name_vec)))
[1] TRUE

Related

R get objects' names from the list of objects

I try to get an object's name from the list containing this object. I searched through similar questions and find some suggestions about using the deparse(substitute(object)) formula:
> my.list <- list(model.product, model.i, model.add)
> lapply(my.list, function(model) deparse(substitute(model)))
and the result is:
[[1]]
[1] "X[[1L]]"
[[2]]
[1] "X[[2L]]"
[[3]]
[1] "X[[3L]]"
whereas I want to obtain:
[1] "model.product", "model.i", "model.add"
Thank you in advance for being of some help!
You can write your own list() function so it behaves like data.frame(), i.e., uses the un-evaluated arg names as entry names:
List <- function(...) {
names <- as.list(substitute(list(...)))[-1L]
setNames(list(...), names)
}
my.list <- List(model.product, model.i, model.add)
Then you can just access the names via:
names(my.list)
names(my.list) #..............
Oh wait, you didn't actually create names did you? There is actually no "memory" for the list function. It returns a list with the values of its arguments but not from whence they came, unless you add names to the pairlist given as the argument.
You won't be able to extract the information that way once you've created my.list.
The underlying way R works is that expressions are not evaluated until they're needed; using deparse(substitute()) will only work before the expression has been evaluated. So:
deparse(substitute(list(model.product, model.i, model.add)))
should work, while yours doesn't.
To save stuffing around, you could employ mget to collect your free-floating variables into a list with the names included:
one <- two <- three <- 1
result <- mget(c("one","two","three"))
result
#$one
#[1] 1
#
#$two
#[1] 1
#
#$three
#[1] 1
Then you can follow #DWin's suggestion:
names(result)
#[1] "one" "two" "three"

How to extract elements from a list with mixed elements

I have a list in R with the following elements:
[[812]]
[1] "" "668" "12345_s_at" "667" "4.899777748"
[6] "49.53333333" "10.10930207" "1.598228663" "5.087437057"
[[813]]
[1] "" "376" "6789_at" "375" "4.899655078"
[6] "136.3333333" "27.82508792" "2.20223398" "5.087437057"
[[814]]
[1] "" "19265" "12351_s_at" "19264" "4.897730912"
[6] "889.3666667" "181.5874908" "1.846451572" "5.087437057"
I know I can access them with something like list_elem[[814]][3] in case that I want to extract the third element of the position 814.
I need to extract the third element of all the list, for example 12345_s_at, and I want to put them in a vector or list so I can compare their elements to another list later on. Below is my code:
elem<-(c(listdata))
lp<-length(elem)
for (i in 1:lp)
{
newlist<-c(listdata[[i]][3]) ###maybe to put in a vector
print(newlist)
}
When I print the results I get the third element, but like this:
[1] "1417365_a_at"
[1] "1416336_s_at"
[1] "1416044_at"
[1] "1451201_s_at"
so I cannot traverse them with an index like newlist[3], because it returns NA. Where is my mistake?
If you want to extract the third element of each list element you can do:
List <- list(c(1:3), c(4:6), c(7:9))
lapply(List, '[[', 3) # This returns a list with only the third element
unlist(lapply(List, '[[', 3)) # This returns a vector with the third element
Using your example and taking into account #GSee comment you can do:
yourList <- list(c("","668","12345_s_at","667", "4.899777748","49.53333333",
"10.10930207", "1.598228663","5.087437057"),
c("","376", "6789_at", "375", "4.899655078","136.3333333",
"27.82508792", "2.20223398", "5.087437057"),
c("", "19265", "12351_s_at", "19264", "4.897730912",
"889.3666667", "181.5874908","1.846451572","5.087437057" ))
sapply(yourList, '[[', 3)
[1] "12345_s_at" "6789_at" "12351_s_at"
Next time you can provide some data using dput on a portion of your dataset so we can reproduce your problem easily.
With purrr you can extract elements and ensure data type consistency:
library(purrr)
listdata <- list(c("","668","12345_s_at","667", "4.899777748","49.53333333",
"10.10930207", "1.598228663","5.087437057"),
c("","376", "6789_at", "375", "4.899655078","136.3333333",
"27.82508792", "2.20223398", "5.087437057"),
c("", "19265", "12351_s_at", "19264", "4.897730912",
"889.3666667", "181.5874908","1.846451572","5.087437057" ))
map_chr(listdata, 3)
## [1] "12345_s_at" "6789_at" "12351_s_at"
There are other map_ functions that enforce the type consistency as well and a map_df() which can finally help end the do.call(rbind, …) madness.
In case you wanted to use the code you typed in your question, below is the fix:
listdata <- list(c("","668","12345_s_at","667", "4.899777748","49.53333333",
"10.10930207", "1.598228663","5.087437057"),
c("","376", "6789_at", "375", "4.899655078","136.3333333",
"27.82508792", "2.20223398", "5.087437057"),
c("", "19265", "12351_s_at", "19264", "4.897730912",
"889.3666667", "181.5874908","1.846451572","5.087437057" ))
v <- character() #creates empty character vector
list_len <- length(listdata)
for(i in 1:list_len)
v <- c(v, listdata[[i]][3]) #fills the vector with list elements (not efficient, but works fine)
print(v)
[1] "12345_s_at" "6789_at" "12351_s_at"

Access atomic vectors shown by Filter(is.atomic, eq) in R

Filter(is.atomic, something)
returns atomic vectors.
1. Weather -example here
> Filter(is.atomic, study)
$region
[1] "Hamburg" "Bremen"
2. mosaic-plot-as-tree-plot -example here
> Map(function(x) Filter(is.atomic, x), ls())
$g
[1] "g"
$lookup
[1] "lookup"
$req.data
[1] "req.data"
$tmp
[1] "tmp"
$tmp1
[1] "tmp1"
Look their positions can be arbitrary, I may have faintest clue of their data-structure so cannot use var$some$...$vector. I feel the need of ?Position. Use your imagination, the examples are not exclusive. How can I access their atomic vectors?
To flatten a list so you can access the atomic vectors, you can use following function:
flatten.list <- function(x){
y <- list()
while(is.list(x)){
id <- sapply(x,is.atomic)
y <- c(y,x[id])
x <- unlist(x[!id],recursive=FALSE)
}
y
}
This function maintains names of the elements. Usage, using the list x from Vincent's answer :
x <- list(
list(1:3, 4:6),
7:8,
list( list( list(9:11, 12:15), 16:20 ), 21:24 )
)
then:
> flatten.list(x)
[[1]]
[1] 7 8
[[2]]
[1] 1 2 3
[[3]]
[1] 4 5 6
[[4]]
[1] 21 22 23 24
...
To recursively do an action on all atomic elements in a list, use rapply() (which is what Vincent handcoded basically).
> rapply(x,sum)
[1] 6 15 15 30 54 90 90
> rapply(x,sum,how='list')
[[1]]
[[1]][[1]]
[1] 6
[[1]][[2]]
[1] 15
[[2]]
[1] 15
...
See also ?rapply
PS : Your code Map(function(x) Filter(is.atomic, x), ls()) doesn't make sense. ls() returns a character vector, so every element of that character vector will be returned as part of the list. This doesn't tell you anything at all.
Next to that, Filter() doesn't do what you believe it does. Taking the example list x, from the answer of Vincent, accessing only the atomic parts of it is pretty easy. Filter() only returns the second element. That's the only atomic element. Filter(is.atomic, x) is 100% equivalent to:
ind <- sapply(x, is.atomic)
x[ind]
Your question is very unclear, to say the least: an example of the input data you have and the desired output would help...
Since you suggest that we "use our imagination", I assume that you have a hierarchical data structure, i.e., a list of lists of...of lists, whose depth is unknown. For instance,
x <- list(
list(1:3, 4:6),
7:8,
list( list( list(9:11, 12:15), 16:20 ), 21:24 )
)
The leaves are vectors, and you want to do "something" with those vectors.
For instance, you may want to concatenate them into a single vector: that is what the unlist function does.
unlist(x)
You could also want all the leaves, in a list, i.e., a list of vectors.
You can easily write a (recursive) function that explores the data structure and progressively builds that list, as follows.
leaves <- function(u) {
if( is.atomic(u) ) { return( list(u) ) }
result <- list()
for(e in u) {
result <- append( result, leaves(e) )
}
return(result)
}
leaves(x)
You could also want to apply a function to all the leaves, while preserving the structure of the data.
happly <- function(u, f, ...) {
if(is.atomic(u)) { return(f(u,...)) }
result <- lapply(u, function(v) NULL) # List of NULLs, with the same names
for(i in seq_along(u)) {
result[[i]] <- happly( u[[i]], f, ... )
}
return( result )
}
happly(x, range) # Apply the "range" function to all the leaves
Filter will return a list. The functions lapply and sapply are typically used to process individual elements of a list object. If you instead want to access them by number using "[" or "[[" then you can determine the range of acceptable numbers with length(object). So object[[length(object)]] would get you the last element (as would ( tail(object, 1) ).

R search variable in all list objects [duplicate]

Filter(is.atomic, something)
returns atomic vectors.
1. Weather -example here
> Filter(is.atomic, study)
$region
[1] "Hamburg" "Bremen"
2. mosaic-plot-as-tree-plot -example here
> Map(function(x) Filter(is.atomic, x), ls())
$g
[1] "g"
$lookup
[1] "lookup"
$req.data
[1] "req.data"
$tmp
[1] "tmp"
$tmp1
[1] "tmp1"
Look their positions can be arbitrary, I may have faintest clue of their data-structure so cannot use var$some$...$vector. I feel the need of ?Position. Use your imagination, the examples are not exclusive. How can I access their atomic vectors?
To flatten a list so you can access the atomic vectors, you can use following function:
flatten.list <- function(x){
y <- list()
while(is.list(x)){
id <- sapply(x,is.atomic)
y <- c(y,x[id])
x <- unlist(x[!id],recursive=FALSE)
}
y
}
This function maintains names of the elements. Usage, using the list x from Vincent's answer :
x <- list(
list(1:3, 4:6),
7:8,
list( list( list(9:11, 12:15), 16:20 ), 21:24 )
)
then:
> flatten.list(x)
[[1]]
[1] 7 8
[[2]]
[1] 1 2 3
[[3]]
[1] 4 5 6
[[4]]
[1] 21 22 23 24
...
To recursively do an action on all atomic elements in a list, use rapply() (which is what Vincent handcoded basically).
> rapply(x,sum)
[1] 6 15 15 30 54 90 90
> rapply(x,sum,how='list')
[[1]]
[[1]][[1]]
[1] 6
[[1]][[2]]
[1] 15
[[2]]
[1] 15
...
See also ?rapply
PS : Your code Map(function(x) Filter(is.atomic, x), ls()) doesn't make sense. ls() returns a character vector, so every element of that character vector will be returned as part of the list. This doesn't tell you anything at all.
Next to that, Filter() doesn't do what you believe it does. Taking the example list x, from the answer of Vincent, accessing only the atomic parts of it is pretty easy. Filter() only returns the second element. That's the only atomic element. Filter(is.atomic, x) is 100% equivalent to:
ind <- sapply(x, is.atomic)
x[ind]
Your question is very unclear, to say the least: an example of the input data you have and the desired output would help...
Since you suggest that we "use our imagination", I assume that you have a hierarchical data structure, i.e., a list of lists of...of lists, whose depth is unknown. For instance,
x <- list(
list(1:3, 4:6),
7:8,
list( list( list(9:11, 12:15), 16:20 ), 21:24 )
)
The leaves are vectors, and you want to do "something" with those vectors.
For instance, you may want to concatenate them into a single vector: that is what the unlist function does.
unlist(x)
You could also want all the leaves, in a list, i.e., a list of vectors.
You can easily write a (recursive) function that explores the data structure and progressively builds that list, as follows.
leaves <- function(u) {
if( is.atomic(u) ) { return( list(u) ) }
result <- list()
for(e in u) {
result <- append( result, leaves(e) )
}
return(result)
}
leaves(x)
You could also want to apply a function to all the leaves, while preserving the structure of the data.
happly <- function(u, f, ...) {
if(is.atomic(u)) { return(f(u,...)) }
result <- lapply(u, function(v) NULL) # List of NULLs, with the same names
for(i in seq_along(u)) {
result[[i]] <- happly( u[[i]], f, ... )
}
return( result )
}
happly(x, range) # Apply the "range" function to all the leaves
Filter will return a list. The functions lapply and sapply are typically used to process individual elements of a list object. If you instead want to access them by number using "[" or "[[" then you can determine the range of acceptable numbers with length(object). So object[[length(object)]] would get you the last element (as would ( tail(object, 1) ).

How do I use `[` correctly with (l|s)apply to select a specific column from a list of matrices?

Consider the following situation where I have a list of n matrices (this is just dummy data in the example below) in the object myList
mat <- matrix(1:12, ncol = 3)
myList <- list(mat1 = mat, mat2 = mat, mat3 = mat, mat4 = mat)
I want to select a specific column from each of the matrices and do something with it. This will get me the first column of each matrix and return it as a matrix (lapply() would give me a list either is fine).
sapply(myList, function(x) x[, 1])
What I can't seem able to do is use [ directly as a function in my sapply() or lapply() incantations. ?'[' tells me that I need to supply argument j as the column identifier. So what am I doing wrong that this does't work?
> lapply(myList, `[`, j = 1)
$mat1
[1] 1
$mat2
[1] 1
$mat3
[1] 1
$mat4
[1] 1
Where I would expect this:
$mat1
[1] 1 2 3 4
$mat2
[1] 1 2 3 4
$mat3
[1] 1 2 3 4
$mat4
[1] 1 2 3 4
I suspect I am getting the wrong [ method but I can't work out why? Thoughts?
I think you are getting the 1 argument form of [. If you do lapply(myList, `[`, i =, j = 1) it works.
After two pints of Britain's finest ale and a bit of cogitation, I realise that this version will work:
lapply(myList, `[`, , 1)
i.e. don't name anything and treat it like I had done mat[ ,1]. Still don't grep why naming j doesn't work...
...actually, having read ?'[' more closely, I notice the following section:
Argument matching:
Note that these operations do not match their index arguments in
the standard way: argument names are ignored and positional
matching only is used. So ‘m[j=2,i=1]’ is equivalent to ‘m[2,1]’
and *not* to ‘m[1,2]’.
And that explains my quandary above. Yeah for actually reading the documentation.
It's because [ is a .Primitive function. It has no j argument. And there is no [.matrix method.
> `[`
.Primitive("[")
> args(`[`)
NULL
> methods(`[`)
[1] [.acf* [.AsIs [.bibentry* [.data.frame
[5] [.Date [.difftime [.factor [.formula*
[9] [.getAnywhere* [.hexmode [.listof [.noquote
[13] [.numeric_version [.octmode [.person* [.POSIXct
[17] [.POSIXlt [.raster* [.roman* [.SavedPlots*
[21] [.simple.list [.terms* [.ts* [.tskernel*
Though this really just begs the question of how [ is being dispatched on matrix objects...

Resources