R: Count number of objects in list [closed] - list

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 6 years ago.
Improve this question
Can someone recommend a function that can allow me to count and return the number of items in a list?
library(stringr)
l <- strsplit(words, "a")
if(# number of items in list l < 1)
next

length(x)
Get or set the length of vectors (including lists) and factors, and of any other R object for which a method has been defined.
lengths(x)
Get the length of each element of a list or atomic vector (is.atomic) as an integer or numeric vector.

Advice for R newcomers like me : beware, the following is a list of a single object :
> mylist <- list (1:10)
> length (mylist)
[1] 1
In such a case you are not looking for the length of the list, but of its first element :
> length (mylist[[1]])
[1] 10
This is a "true" list :
> mylist <- list(1:10, rnorm(25), letters[1:3])
> length (mylist)
[1] 3
Also, it seems that R considers a data.frame as a list :
> df <- data.frame (matrix(0, ncol = 30, nrow = 2))
> typeof (df)
[1] "list"
In such a case you may be interested in ncol() and nrow() rather than length() :
> ncol (df)
[1] 30
> nrow (df)
[1] 2
Though length() will also work (but it's a trick when your data.frame has only one column) :
> length (df)
[1] 30
> length (df[[1]])
[1] 2

I spent ages trying to figure this out but it is simple! You can use length(·). length(mylist) will tell you the number of objects mylist contains.
... and just realised someone had already answered this- sorry!

Let's create an empty list (not required, but good to know):
> mylist <- vector(mode="list")
Let's put some stuff in it - 3 components/indexes/tags (whatever you want to call it) each with differing amounts of elements:
> mylist <- list(record1=c(1:10),record2=c(1:5),record3=c(1:2))
If you are interested in just the number of components in a list use:
> length(mylist)
[1] 3
If you are interested in the length of elements in a specific component of a list use: (both reference the same component here)
length(mylist[[1]])
[1] 10
length(mylist[["record1"]]
[1] 10
If you are interested in the length of all elements in all components of the list use:
> sum(sapply(mylist,length))
[1] 17

You can also use unlist(), which is often useful for handling lists:
> mylist <- list(A = c(1:3), B = c(4:6), C = c(7:9))
> mylist
$A
[1] 1 2 3
$B
[1] 4 5 6
$C
[1] 7 8 9
> unlist(mylist)
A1 A2 A3 B1 B2 B3 C1 C2 C3
1 2 3 4 5 6 7 8 9
> length(unlist(mylist))
[1] 9
unlist() is a simple way of executing other functions on lists as well, such as:
> sum(mylist)
Error in sum(mylist) : invalid 'type' (list) of argument
> sum(unlist(mylist))
[1] 45

Related

Use lapply to plot data in a list and use names of list elements as plot titles [duplicate]

This question already has an answer here:
Adding lists names as plot titles in lapply call in R
(1 answer)
Closed 7 years ago.
If I have the following list:
comp.surv <- list(a = 1:4, b = c(1, 2, 4, 8), c = c(1, 3, 8, 27))
comp.surv
# $a
# [1] 1 2 3 4
#
# $b
# [1] 1 2 4 8
#
# $c
# [1] 1 3 8 27
I can use lapply to plot each list element:
lapply(comp.surv, function(x) plot(x))
However, I want to include the name of each list element as plot title (main). For my example data, the title of each graph would be a,b and c respectively. First thing, is that I have a gsub rule that given comp.surv$a, I return a :
gsub(comp.surv\\$([a-z]+), "\\1", deparse(sustitute((comp.surv$a)))
# "a"
Which is good. However I cannot embed this result into my lapply statement above. Any ideas?
In the mean time I have tried getting round this by creating a function this to include the main parameter:
splot <- function(x){
plot(x, main = gsub(comp.surv\\$([a-z]+), "\\1" deparse(sustitute((x))))
}
lapply(comp.surv, function(x) splot(x))
This will plot each sub-variable of comp.surv, but all the titles are blank.
Can anyone recommend if I am going down the right track?
One possibility would be to loop over the names of the list:
lapply(names(comp.surv), function(x) plot(comp.surv[[x]], main = x))
Or slightly more verbose, loop over the list indices:
lapply(seq_along(comp.surv), function(x) plot(comp.surv[[x]], main = names(comp.surv)[x]))
Is that what you want?
ns=names(comp.surv)
lapply(ns, function(x) plot(comp.surv[[x]], main=x,ylab="y"))

Why this behavior when coercing a list to character via as.character()?

In the process of (mostly) answering this question, I stumbled across something that I feel like I really should already have seen before. Let's say you've got a list:
l <- list(a = 1:3, b = letters[1:3], c = runif(3))
Attempting to coerce l to various types returns an error:
> as.numeric(l)
Error: (list) object cannot be coerced to type 'double'
> as.logical(l)
Error: (list) object cannot be coerced to type 'logical'
However, I'm apparently allowed to coerce a list to character, I just wasn't expecting this result:
> as.character(l)
[1] "1:3"
[2] "c(\"a\", \"b\", \"c\")"
[3] "c(0.874045701464638, 0.0843329173512757, 0.809434881201014)"
Rather, if I'm allowed to coerce lists to character, I would have thought I'd see behavior more like this:
> as.character(unlist(l))
[1] "1" "2" "3" "a" "b"
[6] "c" "0.874045701464638" "0.0843329173512757" "0.809434881201014"
Note that how I specify the list elements originally affects the output of as.character:
l <- list(a = c(1,2,3), b = letters[1:3], c = runif(3))
> as.character(l)
[1] "c(1, 2, 3)"
[2] "c(\"a\", \"b\", \"c\")"
[3] "c(0.344991483259946, 0.0492411875165999, 0.625746068544686)"
I have two questions:
How is as.character dredging up the information from my original creation of the list l in order to spit out 1:3 versus c(1,2,3).
In what circumstances would I want to do this, exactly? When would I want to call as.character() on a list and get output of this form?
For non-trivial lists, as.character uses deparse to generate the strings.
Only if the vector is integer and 1,2,3,...,n - then it deparses as 1:n.
c(1,2,3) is double whereas 1:3 is integer...
No idea :-)
...but look at deparse if you want to understand as.character here:
deparse(c(1L, 2L, 3L)) # 1:3
deparse(c(3L, 2L, 1L)) # c(3L, 2L, 1L)
deparse(c(1, 2, 3)) # c(1, 2, 3)
The help file does say
For lists it deparses the elements individually, except that it extracts the first element of length-one character vectors.
I'd seen this before in trying to answer a question [not online] about grep. Consider:
> x <- list(letters[1:10],letters[10:19])
> grep("c",x)
[1] 1 2
grep uses as.character on x, with the result that, since both have c( in them, both components match. That took a while to figure out.
On "Why does it do this?", I'd guess that one of the members of R core wanted it to do this.

Subset elements in a list based on a logical condition

How can I subset a list based on a condition (TRUE, FALSE) in another list? Please, see my example below:
l <- list(a=c(1,2,3), b=c(4,5,6,5), c=c(3,4,5,6))
l
$a
[1] 1 2 3
$b
[1] 4 5 6 5
$c
[1] 3 4 5 6
cond <- lapply(l, function(x) length(x) > 3)
cond
$a
[1] FALSE
$b
[1] TRUE
$c
[1] TRUE
> l[cond]
Error in l[cond] : invalid subscript type 'list'
This is what the Filter function was made for:
Filter(function(x) length(x) > 3, l)
$b
[1] 4 5 6 5
$c
[1] 3 4 5 6
Another way is to use sapply instead of lapply.
cond <- sapply(l, function(x) length(x) > 3)
l[cond]
[ is expecting a vector, so use unlist on cond:
l[unlist(cond)]
$b
[1] 4 5 6 5
$c
[1] 3 4 5 6
> l[as.logical(cond)]
$b
[1] 4 5 6 5
$c
[1] 3 4 5 6
I recently learned lengths(), which gets the length of each element of a list. This allows us to avoid making another list including logical values as the OP tried.
lengths(l)
#a b c
#3 4 4
Using this in a logical condition, we can subset list elements in l.
l[lengths(l) > 3]
$b
[1] 4 5 6 5
$c
[1] 3 4 5 6
Well im am very new to R but as it is a functional language by far the best solution according to the previous answers is something like:
filter <- function (inputList, selector) sapply(inputList, function (element) selector(element))
Assume you have a complex list like yours:
myList <- list(
a=c(1,2,3),
b=c(4,5,6,5),
c=c(3,4,5,6))
Then you can filter the elements like:
selection <- myList[filter(myList, function (element) length(element) > 3]
Well of course this also works for list that just contain a value at the first level:
anotherList <- list(1, 2, 3, 4)
selection <- myList[filter(anotherList, function (element) element == 2)]
Or you can put it all together like:
filter <- function (inputList, selector) inputList[sapply(inputList, function (element) selector(element))]
cond <- lapply(l, length) > 3
l[cond]
l <- list(a=c(1,2,3), b=c(4,5,6,5), c=c(3,4,5,6))
l[lengths(l) > 3]
$b
[1] 4 5 6 5
$c
[1] 3 4 5 6
If a condition on value is needed:
cond <- lapply(l, function(i) i > 3)
res <- Map(`[`, l, cond)
res
$a
numeric(0)
$b
[1] 4 5 6 5
$c
[1] 4 5 6

Setting vector as a list component in R

I want to create a list which has 1 element called 'a' that holds a vector of doubles.
l<-list('a'=1:1000)
does the trick.
However, what if I want to do it dynamically?
l<-list()
l['a']<-1:1000
does not work!
How can I allocate enough memory when creating the list?
Thanks
Then you do
> l<-list()
> l[['a']]<-1:10
> l
$a
[1] 1 2 3 4 5 6 7 8 9 10
which works fine. With lists, [...] gives you a list with the selected elements, where [[...]] gives you the selected element. See also the help page ?Extract
EDIT :
or, as Tim said, l$a <- 1:10 does the same. The advantage of [[...]] lies in
> l <- list()
> aname <- 'a'
> l[[aname]] <- 1:10
> l
$a
[1] 1 2 3 4 5 6 7 8 9 10

Generating a vector of the number of items in each list item

I have a list containing 98 items. But each item contains 0, 1, 2, 3, 4 or 5 character strings.
I know how to get the length of the list and in fact someone has asked the question before and got voted down for presumably asking such an easy question.
But I want a vector that is 98 elements long with each element being an integer from 0 to 5 telling me how many character strings there are in each list item.
I was expecting the following to work but it did not.
lapply(name.of.list,length())
From my question you will see that I do not really know the nomeclature of lists and items. Feel free to straighten me out.
Farrel, I do not exactly follow as 'item' is not an R type. Maybe you have a list of length 98 where each element is a vector of character string?
In that case, consider this:
R> fl <- list(A=c("un", "deux"), B=c("one"), C=c("eins", "zwei", "drei"))
R> lapply(fl, function(x) length(x))
$A
[1] 2
$B
[1] 1
$C
[1] 3
R> do.call(rbind, lapply(fl, function(x) length(x)))
[,1]
A 2
B 1
C 3
R>
So there is you vector of the length of your list, telling you how many strings each list element has. Note the last do.call(rbind, someList) as we got a list back from lapply.
If, on the other hand, you want to count the length of all the strings at each list position, replace the simple length(x) with a new function counting the characters:
R> lapply(fl, function(x) { sapply(x, function(y) nchar(y)) } )
$A
un deux
2 4
$B
one
3
$C
eins zwei drei
4 4 4
R>
If that is not want you want, maybe you could mock up some example input data?
Edit:: In response to your comments, what you wanted is probably:
R> do.call(rbind, lapply(fl, length))
[,1]
A 2
B 1
C 3
R>
Note that I pass in length, the name of a function, and not length(), the (displayed) body of a function. Because that is easy to mix up, I simply apply almost always wrap an anonymous function around as in my first answer.
And yes, this can also be done with just sapply or even some of the **ply functions:
R> sapply(fl, length)
A B C
2 1 3
R> lapply(fl, length)
[1] 2 1 3
R>
All this seems very complicated - there is a function specifically doing what you were asking for:
lengths #note the plural "s"
Using Dirks sample data:
fl <- list(A=c("un", "deux"), B=c("one"), C=c("eins", "zwei", "drei"))
lengths(fl)
will return a named integer vector:
A B C
2 1 3
The code below accepts a list and returns a vector of lengths:
x = c("vectors", "matrices", "arrays", "factors", "dataframes", "formulas",
"shingles", "datesandtimes", "connections", "lists")
xl = list(x)
fnx = function(xl){length(unlist(strsplit(x, "")))}
lv = sapply(x, fnx)