Calculate in deeper list levels R - r

Imagine, I have list of two levels:
lll <- list()
lll[[1]] <- list(1:10, 1:5, 1:2)
lll[[2]] <- list(10:20, 20:30)
lll
[[1]]
[[1]][[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[1]][[2]]
[1] 1 2 3 4 5
[[1]][[3]]
[1] 1 2
[[2]]
[[2]][[1]]
[1] 10 11 12 13 14 15 16 17 18 19 20
[[2]][[2]]
[1] 20 21 22 23 24 25 26 27 28 29 30
I want calculate means of these sequences. I have written a little function, which works fine:
func <- function(list.list){
lapply(1:length(list.list), function(i) mean(list.list[[i]]))
}
lapply(lll, func)
I don't like in this function, that I have to use anonymous function.
It gets even more complicated when I have list of 3 levels.
Maybe you know better ways to make calculations in which anonymous function would not be included? Should I use higher-order functions (Map, Reduce)?
I know how to write for cycle, but in this case it isn't an option.

Here's a possible solution (using rapply = recursive apply) working at any level of depth :
lll <- list()
lll[[1]] <- list(1:10, 1:5, 1:2)
lll[[2]] <- list(10:20, 20:30)
res <- rapply(lll,mean,how='replace')
> res
[[1]]
[[1]][[1]]
[1] 5.5
[[1]][[2]]
[1] 3
[[1]][[3]]
[1] 1.5
[[2]]
[[2]][[1]]
[1] 15
[[2]][[2]]
[1] 25
Setting argument how='unlist' you will get :
res <- rapply(lll,mean,how='replace')
> res
[1] 5.5 3.0 1.5 15.0 25.0

Related

How to use "for loop" to get couples of indexes every time in R?

Let's assume I have this vector v:
v = seq(1,30,1)
I write this simple loop:
for(i in v) {
print(i)
}
However, I would like to write a loop that gives me, in time, 1:2, 3:4, 5:6, 7:8, etc. I would then get:
[1] 1,2
[1] 3,4
[1] 5,6
[1] 7,8
...
Can anyone help me?
Thanks!
Maybe you can generate v with step of 2.
v = seq(1,30,2)
for(i in v) {
cat(paste(i, i + 1, sep = ','), '\n')
}
#1,2
#3,4
#5,6
#7,8
#9,10
#11,12
#13,14
#...
If you want to keep your approach, try this:
for(i in v[-length(v)]) {
print(c(i, i+1))
}
[1] 1 2
[1] 2 3
[1] 3 4
...
Adding i to a subset.
for(i in v) {
print(v[0:1 + i])
}
# [1] 1 2
# [1] 2 3
# [1] 3 4
# [1] ...
Alternatively you could also consider this:
cbind(v[-length(v)], v[-1])
# [,1] [,2]
# [1,] 1 2
# [2,] 2 3
# [3,] 3 4
# [4,] 4 5
# [5,] 5 6
# [6,] ...
You need to update the print command and use the method range
https://www.w3schools.com/python/ref_func_range.asp
for i in range(0,len(v)-1,2):
print(str(v[i])+","+str(v[i+1]))
In this way you should get
1,2
3,4
5,6
7,8
...
Try this
> for(i in v) if (i%%2) print(c(i,i+1))
[1] 1 2
[1] 3 4
[1] 5 6
[1] 7 8
[1] 9 10
[1] 11 12
[1] 13 14
[1] 15 16
[1] 17 18
[1] 19 20
[1] 21 22
[1] 23 24
[1] 25 26
[1] 27 28
[1] 29 30

How to remove zero vectors from a list of list in r

Problem:
I have a list of two lists of three vectors. I would like to remove the zero vector from each sublist.
Example:
x <- list(x1=c(0,0,0), x2=c(3,4,5), x3=c(45,34,23))
y <- list(y1=c(2,33,4), y2=c(0,0,0), y3=c(4,5,44))
z <- list(x, y)
Try:
I tried this:
res <- lapply(1:2, function(i) {lapply(1:3, function(j) z[[i]][[j]][z[[i]][[j]] != 0])})
Which gave me this:
> res
[[1]]
[[1]][[1]]
numeric(0)
[[1]][[2]]
[1] 3 4 5
[[1]][[3]]
[1] 45 34 23
[[2]]
[[2]][[1]]
[1] 2 33 4
[[2]][[2]]
numeric(0)
[[2]][[3]]
[1] 4 5 44
Problem with the output:
I do not want numeric(0).
Expected output:
x= list(x2, x3)
y=list(y1, y3)
Any idea, please?
You can try a tidyverse if the nested list structure is not important
library(tidyverse)
z %>%
flatten() %>%
keep(~all(. != 0))
$x2
[1] 3 4 5
$x3
[1] 45 34 23
$y1
[1] 2 33 4
$y3
[1] 4 5 44
Given your structure of list of lists I would go with the following:
filteredList <- lapply(z, function(i) Filter(function(x) any(x != 0), i))
x <- filteredList[[1]]
y <- filteredList[[2]]
x
##$`x2`
##[1] 3 4 5
##$x3
##[1] 45 34 23
y
##$`y1`
##[1] 2 33 4
##$y3
##[1] 4 5 44
define z as
z <- c(x, y)
# z <- unlist(z, recursive = F) if you cannot define z by yourself.
then use:
z[sapply(z, any)]
#$`x2`
#[1] 3 4 5
#$x3
#[1] 45 34 23
#$y1
#[1] 2 33 4
#$y3
#[1] 4 5 44
Please note:
As in the tradition of lang C. Every integer/ numeric != 0 will be casted to TRUE. So in this task we can use this logic. ?any will eval FALSE if all values are 0.
Or:
x <- list(x1=c(0,0,0), x2=c(3,4,5), x3=c(45,34,23))
y <- list(y1=c(2,33,4), y2=c(0,0,0), y3=c(4,5,44))
z <- list(x, y)
lapply(z, function(a) a[unlist(lapply(a, function(b) !identical(b, rep(0,3))))])
#[[1]]
#[[1]]$`x2`
#[1] 3 4 5
#
#[[1]]$x3
#[1] 45 34 23
#
#
#[[2]]
#[[2]]$`y1`
#[1] 2 33 4
#
#[[2]]$y3
#[1] 4 5 44
with purrr it can be really compact
library(purrr)
map(z, keep ,~all(.!=0))
# [[1]]
# [[1]]$x2
# [1] 3 4 5
#
# [[1]]$x3
# [1] 45 34 23
#
#
# [[2]]
# [[2]]$y1
# [1] 2 33 4
#
# [[2]]$y3
# [1] 4 5 44
If it wasn't for the annoying warnings we could do just map(z, keep , all)

How to name the element of the list in r?

Suppose I have this list:
my_variable <- list()
x <- c(1,2,3,4)
y <- c(4,5,7,3)
for ( i in 1:4){
my_variable[[i]] <- x[i]*y[i]+2
}
Then I will get this:
[[1]]
[1] 6
[[2]]
[1] 12
[[3]]
[1] 23
[[4]]
[1] 14
How to name the element of the output, like this:
> my_variable
First_result
[1] 6
Second_result
[1] 12
and so on.
You could do it with the paste0 and names
# So first you define vector of names:
names1 <- c("First","Second","Third","Fourth")
# And second you paste them to your list
names(my_variable) <- paste0(names1,"_result", sep = "")
#And the output
$First_result
[1] 6 12 23 14
$Second_result
[1] 6 12 23 14
$Third_result
[1] 6 12 23 14
$Fourth_result
[1] 6 12 23 14

Replace all values of a recursive list with values of a vector

Say, I have the following recursive list:
rec_list <- list(list(rep(1,5), 10), list(rep(100, 4), 20:25))
rec_list
[[1]]
[[1]][[1]]
[1] 1 1 1 1 1
[[1]][[2]]
[1] 10
[[2]]
[[2]][[1]]
[1] 100 100 100 100
[[2]][[2]]
[1] 20 21 22 23 24 25
Now, I would like to replace all the values of the list, say, with the vector seq_along(unlist(rec_list)), and keep the structure of the list. I tried using the empty index subsetting like
rec_list[] <- seq_along(unlist(rec_list))
But this doesn't work.
How can I achieve the replacement while keeping the original structure of the list?
You can use relist:
relist(seq_along(unlist(rec_list)), skeleton = rec_list)
# [[1]]
# [[1]][[1]]
# [1] 1 2 3 4 5
#
# [[1]][[2]]
# [1] 6
#
#
# [[2]]
# [[2]][[1]]
# [1] 7 8 9 10
#
# [[2]][[2]]
# [1] 11 12 13 14 15 16
If you wanted to uniquely index each element of a nested list, you could start with the rapply() function which is the recursive form of the apply() family. Here I use a special function that can uniquely index across a list of any structure
rapply(rec_list,
local({i<-0; function(x) {i<<-i+length(x); i+seq_along(x)-length(x)}}),
how="replace")
other functions are simplier, for example if you just wanted to seq_along each subvector
rapply(rec_list, seq_along, how="replace")

Summary a list of integers into two columns in R

This is what I've got (a list):
>head(indexes)
[[1]]
numeric(0)
[[2]]
[1] 12
[[3]]
[1] 13
[[4]]
[1] 2 3
[[5]]
[1] 25
[[6]]
[1] 26
> all(vapply(indexes, is.numeric, TRUE)) # (note that..)
[1] TRUE
.. and this is what I want (same information for me):
>head(res,6)
[,1] [,2]
[1,] 2 12
[2,] 3 13
[3,] 4 2
[4,] 4 3
[5,] 5 25
[6,] 6 36
Is there a clever way to do this?
I tried a trick with naming the list:
names(indexes) <- 1:lenght(indexes)
res <- c(indexes, recursive=TRUE)
res <- cbind(as.integer(names(res)), res)
But R (such a kind damn kid!) breaks everything down by renaming the identical rows in an ambiguous fashion:
>head(res)
res
2 2 2
3 3 3
41 41 2
42 42 3
5 5 5
6 6 6
# ... (think about what happens around lines 3675.. 41158..)
.. if this was the clever way, how do I prevent the renaming?
Wops! Okay, nailed it:
res <- cbind(
rep(1:length(indexes), vapply(indexes,length,1)),
c(indexes,recursive=TRUE)
)
.. just tell me if anyone found a better way, then :)

Resources