You can easily make lists of lists
list1 <- list(a = 2, b = 3)
list2 <- list(c = "a", d = "b")
mylist <- list(list1, list2)
mylist is now a list that contains two lists. To access list1 you can use mylist[[1]]. If you want to be able to something like mylist$list1 then you need to do somethingl like
mylist <- list(list1 = list1, list2 = list2)
# Now you can do the following
mylist$list1
Edit: To reply to your edit. Just use double bracket indexing
a <- list_all[[1]]
a[[1]]
#[1] 1
a[[2]]
#[1] 2
Answer from Dason on Stack OverflowYou can easily make lists of lists
list1 <- list(a = 2, b = 3)
list2 <- list(c = "a", d = "b")
mylist <- list(list1, list2)
mylist is now a list that contains two lists. To access list1 you can use mylist[[1]]. If you want to be able to something like mylist$list1 then you need to do somethingl like
mylist <- list(list1 = list1, list2 = list2)
# Now you can do the following
mylist$list1
Edit: To reply to your edit. Just use double bracket indexing
a <- list_all[[1]]
a[[1]]
#[1] 1
a[[2]]
#[1] 2
Using your example::
list1 <- list()
list1[1] = 1
list1[2] = 2
list2 <- list()
list2[1] = 'a'
list2[2] = 'b'
list_all <- list(list1, list2)
Use '[[' to retrieve an element of a list:
b = list_all[[1]]
b
[[1]]
[1] 1
[[2]]
[1] 2
class(b)
[1] "list"
Altough your example isn't reproducible, I get a list of lists with the following similar code:
potential_dups <- rep(list(list()), 10)
nearest10 <- matrix(rnorm(100), nrow=10)
for (i in 1:10) {
for (j in 1:10) {
if (nearest10[i, j] < 0.35 & nearest10[i, j] > 0) {
potential_dups[[i]] <- append(potential_dups[[i]], nearest10[i, j])
}
}
}
To remove empty lists you can do this:
potential_dups[sapply(potential_dups, function(x) length(x) > 0)]
Here is a nicer (better readable and more efficient) way:
mat <- nearest10
mat[mat >= 0.35 | mat <= 0] <- NA
potential_dups <- apply(mat,1,function(x) as.list(na.omit(x)))
However, I can't imagine why you want this output. It doesn't seem the most useful. maybe you could use the following instead?
potential_dups <- apply(mat,1,function(x) c(na.omit(x)))
Actually you are already close to your desired output, but you may need another list() within append, e.g.,
newl <- list()
newl <- append(newl, list(list(a = 1, b = "x")))
newl <- append(newl, list(list(a = 15, b = "y")))
newl <- append(newl, list(list(a = 10, b = "z")))
such that
> newl
[[1]]
[[1]]
b
[1] "x"
[[2]]
[[2]]
b
[1] "y"
[[3]]
[[3]]
b
[1] "z"
If you want to sort by $a, you can try
> newl[order(sapply(newl, `[[`, "a"))]
[[1]]
[[1]]
b
[1] "x"
[[2]]
[[2]]
b
[1] "z"
[[3]]
[[3]]
b
[1] "y"
We could do a split
lst1 <- unname(split(newl, as.integer(gl(length(newl), 2, length(newl)))))
A short version:
sapply(GroupedList, nrow)
I would suggest this approach. You can use lapply() as you have a list and the bind the results with do.call() and rbind():
#Data
List <- list(structure(list(preds = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L), ground_truth = c(1L, 0L, 1L, 1L, 0L, 1L, 1L, 1L,
1L, 0L, 1L)), class = "data.frame", row.names = c("21528", "14033",
"3770", "16734", "20867", "26342", "687", "7501", "15543", "13239",
"3403")), structure(list(preds = c(1L, 1L, 1L, 1L, 1L, 1L), ground_truth = c(1L,
1L, 0L, 1L, 1L, 1L)), class = "data.frame", row.names = c("5278",
"4745", "12622", "26877", "441", "20626")), structure(list(preds = c(1L,
1L), ground_truth = c(1L, 1L)), class = "data.frame", row.names = c("7431",
"16675")), structure(list(preds = integer(0), ground_truth = integer(0)), row.names = character(0), class = "data.frame"))
The code:
#Obtain dim
O <-as.data.frame(do.call(rbind,lapply(List,function(x) dim(x)[1])))
#Format
O$List <- rownames(O)
O <- O[,c(2,1)]
names(O)[2]<-'count'
rownames(O)<-NULL
Output:
List count
1 1 11
2 2 6
3 3 2
4 4 0
Update: Here another approach using for()
#Data
List2 <- list(l1 = list(structure(list(preds = c(1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L), ground_truth = c(1L, 0L, 1L, 1L, 0L, 1L,
1L, 1L, 1L, 0L, 1L)), class = "data.frame", row.names = c("21528",
"14033", "3770", "16734", "20867", "26342", "687", "7501", "15543",
"13239", "3403"))), l2 = list(structure(list(preds = c(1L, 1L,
1L, 1L, 1L, 1L), ground_truth = c(1L, 1L, 0L, 1L, 1L, 1L)), class = "data.frame", row.names = c("5278",
"4745", "12622", "26877", "441", "20626"))), l3 = list(structure(list(
preds = c(1L, 1L), ground_truth = c(1L, 1L)), class = "data.frame", row.names = c("7431",
"16675"))), l4 = list(structure(list(preds = integer(0), ground_truth = integer(0)), row.names = character(0), class = "data.frame")))
The code:
#Create empty list to save results
elist <- list()
#Loop
for(i in 1:length(List2))
{
#Check dim
if(dim(List2[[i]][[1]])[1]>0)
{
df <- data.frame(name=names(List2[i]),count=dim(List2[[i]][[1]])[1])
elist[[i]] <- df
}
}
#Now bind
O <- do.call(rbind,elist)
Output:
name count
1 l1 11
2 l2 6
3 l3 2
Could it be this, what you want to have:
# Initial list:
myList <- list()
# Now the new experiments
for(i in 1:3){
myList[[length(myList)+1]] <- list(sample(1:3))
}
myList
outlist <- list(resultsa)
outlist[2] <- list(resultsb)
outlist[3] <- list(resultsc)
append's help file says it is for vectors. But it can be used here. I thought I had tried that before but there were some strange anomalies in the OP's code that may have mislead me:
outlist <- list(resultsa)
outlist <- append(outlist,list(resultsb))
outlist <- append(outlist,list(resultsc))
Same results.
Try this:
list.of.lists[order(sapply(list.of.lists,'[[',1))]
You have a lot of structure in your list.of.lists. Depending on other processing you need to do, you might want to make it into a two-dimensional list like so:
list.2d <- sapply(list.of.lists, cbind)
and, possibly, from there, into a data frame like this:
df <- data.frame(t(list.2d))
(Technically, a data frame is a type of list.) Sorting by a particular set of columns, and extracting subsets of elements can then be a bit more conventional. (Though I also really like the accepted answer here.)
Here is an approach using rlist and purr
do.call(rlist::list.zip, out) %>%
purrr::map(~ do.call(rbind, .))
Or, with even more purrr:
library(purrr)
out %>%
do.call(rlist::list.zip, .) %>%
map(~ reduce(., rbind))
When your frames are all structured similarly or the same and you intend to to the same "thing" to all of them, it is generally best to work with a list of frames instead of individual elements.
out <- replicate(4, rep(list(mtcars[c(1,3),1:3]), 2), simplify = FALSE)
out[[1]][[1]]
# mpg cyl disp
# Mazda RX4 21.0 6 160
# Datsun 710 22.8 4 108
lapply(1:2, function(ind) do.call(rbind, lapply(out, `[[`, ind)))
# [[1]]
# mpg cyl disp
# Mazda RX4 21.0 6 160
# Datsun 710 22.8 4 108
# Mazda RX41 21.0 6 160
# Datsun 7101 22.8 4 108
# Mazda RX42 21.0 6 160
# Datsun 7102 22.8 4 108
# Mazda RX43 21.0 6 160
# Datsun 7103 22.8 4 108
# [[2]]
# mpg cyl disp
# Mazda RX4 21.0 6 160
# Datsun 710 22.8 4 108
# Mazda RX41 21.0 6 160
# Datsun 7101 22.8 4 108
# Mazda RX42 21.0 6 160
# Datsun 7102 22.8 4 108
# Mazda RX43 21.0 6 160
# Datsun 7103 22.8 4 108
If you're already using dplyr or data.table, then these are relatively equivalent but often a little safer:
lapply(1:2, function(ind) data.table::rbindlist(lapply(out, `[[`, ind), fill = TRUE, use.names = TRUE))
lapply(1:2, function(ind) dplyr::bind_rows(lapply(out, `[[`, ind)))
If you really want to do this, then, because the elements of the lists in each element of the array do not have names, you can't index by a character vector. In your example, there is no x[1][[ "a" ]]:
> x[1][[ "a" ]]
NULL
If there are no names then you need to index by a numeric:
> x[1][[ 1 ]] <- 1
[1] 1
It would seem more logical to have a list though than an array:
> y <- vector(mode = "list", length = 10)
> y
[[1]]
NULL
[[2]]
NULL
[[3]]
NULL
[[4]]
NULL
[[5]]
NULL
....
What you're calling an "array" is usually just called a list in R. You're getting tripped up by the difference between [ and [[ for lists. See the section "Recursive (list-like) objects" in help("[").
x[[1]][["a"]] <- 1
UPDATE:
Note that the solution above creates a list of named vectors. In other words, something like
x[[1]][["a"]] <- 1
x[[1]][["b"]] <- 1:2
won't work because you can't assign multiple values to one element of a vector. If you want to be able to assign a vector to a name, you can use a list of lists.
x[[1]] <- as.list(x[[1]])
x[[1]][["b"]] <- 1:2
I have found another way which avoids the problem mentioned above, namely that combine has to create a new list first and later only append lists.
Also, the real function I am using actually returns a list of lists, so the following proved useful:
combine_custom <- function(list1, list2) {
if (plotrix::listDepth(list1$l) > plotrix::listDepth(list2$l)) {
ls <- c(list1$l, list(list2$l))
} else {
ls <- c(list(list1$l), list(list2$l))
}
ns <- c(list1$n, list2$n)
return(list(l = ls, n = ns))
}
This is not perfect if the function can return lists of varying nesting depths, but it works in my case.
Thank you @Maria H., you solved my problem! The 'plotrix' package didn't work for me, but I used 'collapse' and it worked fine:
combine_custom1 <- function(a, b) {
if (collapse::ldepth(a) > collapse::ldepth(b)) {
ls <- c(a, list(b))
} else {
ls <- c(list(a), list(b))
}
return(ls)
}
In R, indexing starts from 1 and not 0 - difference between Python and R. So, if we change it to 1 and 2, it works. In addition, 1:length may be replaced with less buggy seq_along
for( j in seq_along(mylist)){
print(j)
list1 = mylist[[j]]
print(list1)
a=list1[[1]]
b=list1[[2]]
# usage of a and b
}
[1] 1
[[1]]
[1] 10
[[2]]
[1] 20
[1] 2
[[1]]
[1] 30
[[2]]
[1] 40
NOTE: list1, a, b are objects created within the loop and this gets updated in each iteration. It is not clear about the final outcome
A translation of your python code might be something like below
> for (lst in mylist) {
+ a <- lst[[1]]
+ b <- lst[[2]]
+ print(c(a, b))
+ }
[1] 10 20
[1] 30 40
Try
lapply(z, function(x) as.numeric(unlist(x)))
## [[1]]
## [1] 1 2 5 3 4 4 7
##
## [[2]]
## [1] 1 2 3 4
z1 <- lapply(z, function(x) names(unlist(x)))
z1 <- lapply(z1, function(x) gsub(".*\\.", "", x))
n <- max(sapply(z1, length))
z1 <- lapply(z1, `length<-`, value = n)
setNames(as.data.frame(z1), paste0("Column", seq_along(z1)))
# Column1 Column2
#1 a a
#2 b b
#3 c a
#4 a b
#5 b <NA>
#6 d <NA>
#7 e <NA>
