Conditional merging of two lists in R - r

I am trying to combine two lists that complement each other, where one contains half the set of values and the second the other half:
v1 <- c(1,2,2,4)
v2 <- c(NULL)
v3 <- c(1,2,2,4)
l1 <- list(v1,v2,v3)
v1b <- c(NULL)
v2b <- c(1,2,2,4)
v3b <- c(NULL)
l2 <- list(v1b,v2b,v3b)
> l1
[[1]]
[1] 1 2 2 4
[[2]]
NULL
[[3]]
[1] 1 2 2 4
> l2
[[1]]
NULL
[[2]]
[1] 1 2 2 4
[[3]]
NULL
The desired result is:
[[1]]
[1] 1 2 2 4
[[2]]
[1] 1 2 2 4
[[3]]
[1] 1 2 2 4
I tried several ways. This is the closest I got:
> sapply(l1, function(x) ifelse(x == "NULL", l2[[x]], x))
[[1]]
[1] 1 2 2 4
[[2]]
logical(0)
[[3]]
[1] 1 2 2 4
Any help is appreciated.

Related

purrr - how to apply recursively a function with changing arguments

Ideally I would like to make use of purrr's accumulate function or similar.
Let's say I want to make use of utils::combn function iteratively, and get all the intermediate results (ideally put inside a list of lists).
In example below, initially, parameter x = 4, thus m will be also 4 (but (x, m) could be (5, 5), (6, 6), ...). Then, after first loop, x will be previous result, whilst m goes down by one, iteratively until m = 2.
n1 <- combn(x = 4, m = 4, simplify = FALSE)
n2 <- map(n1, ~ combn(.x, 3, simplify = FALSE))
n3 <- map(n2, ~ map(., ~ combn(.x, 2, simplify = FALSE)))
> n1
[[1]]
[1] 1 2 3 4
> n2
[[1]]
[[1]][[1]]
[1] 1 2 3
[[1]][[2]]
[1] 1 2 4
[[1]][[3]]
[1] 1 3 4
[[1]][[4]]
[1] 2 3 4
> n3
[[1]]
[[1]][[1]]
[[1]][[1]][[1]]
[1] 1 2
[[1]][[1]][[2]]
[1] 1 3
[[1]][[1]][[3]]
[1] 2 3
[[1]][[2]]
[[1]][[2]][[1]]
[1] 1 2
[[1]][[2]][[2]]
[1] 1 4
[[1]][[2]][[3]]
[1] 2 4
[[1]][[3]]
[[1]][[3]][[1]]
[1] 1 3
[[1]][[3]][[2]]
[1] 1 4
[[1]][[3]][[3]]
[1] 3 4
[[1]][[4]]
[[1]][[4]][[1]]
[1] 2 3
[[1]][[4]][[2]]
[1] 2 4
[[1]][[4]][[3]]
[1] 3 4
As you can imagine, I want to get all possible combinations, e.g.:
choose(4, 4) -> choose(result, 3) -> choose(result, 2).
Any help or ideas would be much appreciated.
You can use accumulate + map_depth:
combn_recur <- function(n) {
accumulate(c(n, 0:(n-2)),
~ map_depth(.x, .y, combn, m = n-.y, simplify = FALSE))[-1]
}
all.equal(combn_recur(4), c(n1, n2, n3))
# TRUE
combn_recur(3)
# [[1]]
# [1] 1 2 3
#
# [[2]]
# [[2]][[1]]
# [1] 1 2
#
# [[2]][[2]]
# [1] 1 3
#
# [[2]][[3]]
# [1] 2 3
combn_recur(2)
# [[1]]
# [1] 1 2
combn_recur(1)
# Error in .f(.x[[i]], ...) : n < m

R: how to convert a sparse binary matrix represented by row-indexed lists to column-indexed lists

Assuming I have a sparse m by n binary matrix, and I already use a row-indexed lists to represent the ones. For example, the following 3 by 3 matrix
[,1] [,2] [,3]
[1,] 1 1 0
[2,] 0 1 0
[3,] 0 0 1
is represented by a list M_row:
> M_row
[[1]]
[1] 1 2
[[2]]
[1] 2
[[3]]
[1] 3
Here the i-th element in the list corresponds to the positions of ones in the i-th row.
I want to convert this list to a column-indexed list, where the j-th element in the new list corresponds to the (row) positions of ones in the j-th column. For the previous example, I want:
> M_col
[[1]]
[1] 1
[[2]]
[1] 1 2
[[3]]
[1] 3
Is there an efficient way to do this without writing many loops?
Try this
M_row <- list(1:2 , 2, 3) # this is the beginning list
#----------------------------------
m <- matrix(0 , length(M_row) , length(M_row))
for(i in 1:nrow(m)) {
m[ i , M_row[[i]]] <- 1
}
M_col <- apply(m , 2 , \(x) which(x == 1))
#----------------------------------
M_col # this is the required list
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] 1 2
#>
#> [[3]]
#> [1] 3
Here is an algorithm that doesn't create the matrix.
Get the number of columns with sapply/max and create a results list M_col of the required length;
for each input list member, update M_col by appending the row number to it.
M_row <- list(1:2 , 2, 3)
Max_col <- max(sapply(M_row, max))
M_col <- vector("list", length = Max_col)
for(i in seq_along(M_row)) {
for(j in M_row[[i]]) {
M_col[[j]] <- c(M_col[[j]], i)
}
}
M_col
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] 1 2
#>
#> [[3]]
#> [1] 3
Created on 2022-06-19 by the reprex package (v2.0.1)
You could use stack + unstack:
M_row <- list(1:2 , 2, 3) # this is the beginning list
d <- type.convert(stack(setNames(M_row, seq_along(M_row))), as.is = TRUE)
d
values ind
1 1 1
2 2 1
3 2 2
4 3 3
d is the row, column combinations where values represents the row while ind represents the columns:
columnwise:
unstack(d, ind~values)
$`1`
[1] 1
$`2`
[1] 1 2
$`3`
[1] 3
Rowwise:
unstack(d, values~ind)
$`1`
[1] 1 2
$`2`
[1] 2
$`3`
[1] 3

Get subsets between one element and the previous same element

Consider a vector:
vec <- c(1, 3, 4, 3, 3, 1, 1)
I'd like to get, for each element of the vector, a subset of the values in between the nth element and its previous occurrence.
The expected output is:
f(vec)
# [[1]]
# [1] 1
#
# [[2]]
# [1] 3
#
# [[3]]
# [1] 4
#
# [[4]]
# [1] 3 4 3
#
# [[5]]
# [1] 3 3
#
# [[6]]
# [1] 1 3 4 3 3 1
#
# [[7]]
# [1] 1 1
We may loop over the sequence of the vector, get the index of the last match of the same element ('i1') from the previous elements of the vector and get the sequence (:) to subset the vector
lapply(seq_along(vec), function(i) {
i1 <- tail(which(vec[1:(i-1)] == vec[i]), 1)[1]
i1[is.na(i1)] <- i
vec[i1:i]
})
-output
[[1]]
[1] 1
[[2]]
[1] 3
[[3]]
[1] 4
[[4]]
[1] 3 4 3
[[5]]
[1] 3 3
[[6]]
[1] 1 3 4 3 3 1
[[7]]
[1] 1 1

Getting all splits of numeric sequence in R

I'm trying to get all the possible splits of a sequence [1:n] in R. E.g.:
getSplits(0,3)
Should return all possible splits of the sequence 123, in other words (in a list of vectors):
[1] 1
[2] 1 2
[3] 1 2 3
[4] 1 3
[5] 2
[6] 2 3
[7] 3
Now I've created a function which does get to these vectors recursively, but having trouble combining them into one as above. My function is:
getSplits <- function(currentDigit, lastDigit, split) {
splits=list();
for (nextDigit in currentDigit: lastDigit)
{
currentSplit <- c(split, c(nextDigit));
print(currentSplit);
if(nextDigit < lastDigit) {
possibleSplits = c(list(currentSplit), getSplits(nextDigit+1, lastDigit, currentSplit));
}else{
possibleSplits = currentSplit;
}
splits <- c(splits, list(possibleSplits));
}
return(splits);
}
Where printing each currentSplit results in all the right vectors I need, but somehow the final returnt list (splits) nests them into deeper levels of lists, returning:
[1] 1
[[1]][[2]]
[[1]][[2]][[1]]
[1] 1 2
[[1]][[2]][[2]]
[1] 1 2 3
[[1]][[3]]
[1] 1 3
[[2]]
[[2]][[1]]
[1] 2
[[2]][[2]]
[1] 2 3
[[3]]
[1] 3
For the corresponding function call getSplits(1, 3, c()).
If anyone could help me out on getting this to work the way I described above, it'd be much appreciated!
character vector output
Try combn:
k <- 3
s <- unlist(lapply(1:k, combn, x = k, toString))
s
## [1] "1" "2" "3" "1, 2" "1, 3" "2, 3" "1, 2, 3"
data frame output
If you would prefer that the output be in the form of a data frame:
read.table(text = s, header = FALSE, sep = ",", fill = TRUE, col.names = 1:k)
giving:
X1 X2 X3
1 1 NA NA
2 2 NA NA
3 3 NA NA
4 1 2 NA
5 1 3 NA
6 2 3 NA
7 1 2 3
list output
or a list:
lapply(s, function(x) scan(textConnection(x), quiet = TRUE, sep = ","))
giving:
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
[[4]]
[1] 1 2
[[5]]
[1] 1 3
[[6]]
[1] 2 3
[[7]]
[1] 1 2 3
Update: Have incorporated improvement mentioned in comments as well as one further simplification and also added data frame and list output.
Here is another approach:
f <- function(nums) sapply(1:length(nums), function(x) t(combn(nums, m = x)))
f(1:3)
This yields
[[1]]
[,1]
[1,] 1
[2,] 2
[3,] 3
[[2]]
[,1] [,2]
[1,] 1 2
[2,] 1 3
[3,] 2 3
[[3]]
[,1] [,2] [,3]
[1,] 1 2 3
The OP is looking for the Power set of c(1,2,3). There are several packages that will quickly get you this in one line. Using the package rje, we have:
library(rje)
powerSet(c(1,2,3))
[[1]]
numeric(0)
[[2]]
[1] 1
[[3]]
[1] 2
[[4]]
[1] 1 2
[[5]]
[1] 3
[[6]]
[1] 1 3
[[7]]
[1] 2 3
[[8]]
[1] 1 2 3
... and with iterpc:
library(iterpc)
getall(iterpc(c(2,1,1,1), 3, labels = 0:3))
[,1] [,2] [,3]
[1,] 0 0 1
[2,] 0 0 2
[3,] 0 0 3
[4,] 0 1 2
[5,] 0 1 3
[6,] 0 2 3
[7,] 1 2 3
More generally,
n <- 3
getall(iterpc(c(n-1,rep(1, n)), n, labels = 0:n)) ## same as above

how to write code for find index of element in subset?

library(gRbase)
m<-combn(1:4,2,simplify=FALSE)
m
[[1]]
[1] 1 2
[[2]]
[1] 1 3
[[3]]
[1] 1 4
[[4]]
[1] 2 3
[[5]]
[1] 2 4
[[6]]
[1] 3 4
I want output for element 2 fn(2):1,4,5
res <- vector("numeric"); for( i in seq_along(m)){ if(2 %in% m[[i]]){res<-c(res,i)}}
>res
[1] 1 4 5
To encapsulate in a function:
fn <- function(lis , item){
res <- vector("numeric")
for( i in seq_along(m)){ if(2 %in% m[[i]]){res<-c(res,i)}}
res}
> fn(m,item)
[1] 1 4 5
Here's another methos which seems less obvious to me: I'm posting the sequence of intermediate steps I used to get there:
sapply(seq_along(m),function(x) match(x=2,m[[x]]) )
#[1] 2 NA NA 1 1 NA
as.logical(sapply(seq_along(m),function(x) match(x=2,m[[x]]) ) )
#[1] TRUE NA NA TRUE TRUE NA
which(as.logical(sapply(seq_along(m),function(x) match(x=2,m[[x]]) ) ) )
#[1] 1 4 5
which(vapply(m, function(x) 2 %in% x, FUN.VALUE = FALSE))
#[1] 1 4 5

Resources