How to create bijection between two lists? - r

Good afternoon !
I'm wanting to transform a list like the following :
list_1= list(c(1,30,25),c(51,70),c(102,130,125))
to be :
list_2=list(c(1,2,3),c(4,5),c(6,7,8))
I know that we can retrieve list_1 lengths with :
lengths(list_1)
3 2 3
The list_2 represent indices of list_1 elements ( in case we unlist them ) .
I hope my question is clear , thank you for help in advance !

Using split.
ll <- lengths(list_1)
unname(split(seq(unlist(list_1)), rep(seq(ll), ll)))
# [[1]]
# [1] 1 2 3
#
# [[2]]
# [1] 4 5
#
# [[3]]
# [1] 6 7 8

An option with relist
relist(seq_along(unlist(list_1)), skeleton = list_1)
#[[1]]
#[1] 1 2 3
#[[2]]
#[1] 4 5
#[[3]]
#[1] 6 7 8

Related

How to check if the given value belong to the vectors in list?

Suppose we have a value y=4, and a list of vectors, I want to check if this value belongs to any vector in the list if yes, I will add this value to all the elements of vectors.
y<-4
M<- list( c(1,3,4,6) , c(2,3,5), c(1,3,6) ,c(1,4,5,6))
> M
[[1]]
[1] 1 3 4 6
[[2]]
[1] 2 3 5
[[3]]
[1] 1 3 6
[[4]]
[1] 1 4 5 6
The outcomes will be similar to :
> R
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10
We can use keep which only keeps elements that satisfy a predicate. In this case, it is only keeping the vectors that contain y.
We then add y to each of the vectors.
library('tidyverse')
keep(M, ~y %in% .) %>%
map(~. + y)
Here is a simple hacky way to do this:
lapply(M[sapply(M, function(x){y %in% x})],function(x){x+y})
returning:
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10
Logic: use sapply to work out which parts of M have a 4 in, then add 4 to those with lapply
You can do this with...
lapply(M[sapply(M, `%in%`, x=y)], `+`, y)
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10
Here is a method with lapply and set functions.
# loop through M, check length of intersect
myList <- lapply(M, function(x) if(length(intersect(y, x)) > 0) x + y else NULL)
# now subset, dropping the NULL elements
myList <- myList[lengths(myList) > 0]
this returns
myList
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10
Wow! everyone has given great answers, just including the use of Map functionality.
Map("+",M[unlist(Map("%in%", y,M))],y)
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10

R : Convert nested list into a one level list [duplicate]

This question already has answers here:
How to flatten a list of lists?
(3 answers)
Closed 5 years ago.
I got the following y nested list :
x1=c(12,54,2)
x2=c(2,88,1)
x3=c(4,8)
y=list()
y[[1]]=x1
y[[2]]=list(x2,x3)
y
[[1]]
[1] 12 54 2
[[2]]
[[2]][[1]]
[1] 2 88 1
[[2]][[2]]
[1] 4 8
I would like to extract all elements from this nested list and put them into a one level list, so my expected result should be :
y_one_level_list
[[1]]
[1] 12 54 2
[[2]]
[1] 2 88 1
[[3]]
[1] 4 8
Obviously ma real problem involve a deeper nested list, how would you solve it? I tried rapply but I failed.
Try lapply together with rapply:
lapply(rapply(y, enquote, how="unlist"), eval)
#[[1]]
#[1] 12 54 2
#[[2]]
#[1] 2 88 1
#[[3]]
#[1] 4 8
It does work for deeper lists either.
You can try this:
flatten <- function(lst) {
do.call(c, lapply(lst, function(x) if(is.list(x)) flatten(x) else list(x)))
}
flatten(y)
#[[1]]
#[1] 12 54 2
#[[2]]
#[1] 2 88 1
#[[3]]
#[1] 4 8

R: enumerating sequences of permutations

I want to enumerate the distinct sequences of different permutations, and I'm using the function permn. I understand for 2!, I can just use permn(2) and that will enumerate 1, 2 and 2, 1.
> library(combinat)
> permn(2)
[[1]]
[1] 1 2
[[2]]
[1] 2 1
I want to do the same thing for the numbers 7 and 8. So what should I pass into the function so that it will return something like this?
> permn(...)
[[1]]
[1] 7 8
[[2]]
[1] 8 7
permn(c(7,8))
#[[1]]
#[1] 7 8
#
#[[2]]
#[1] 8 7

Split a vector by its sequences [duplicate]

This question already has answers here:
Create grouping variable for consecutive sequences and split vector
(5 answers)
Closed 5 years ago.
The following vector x contains the two sequences 1:4 and 6:7, among other non-sequential digits.
x <- c(7, 1:4, 6:7, 9)
I'd like to split x by its sequences, so that the result is a list like the following.
# [[1]]
# [1] 7
#
# [[2]]
# [1] 1 2 3 4
#
# [[3]]
# [1] 6 7
#
# [[4]]
# [1] 9
Is there a quick and simple way to do this?
I've tried
split(x, c(0, diff(x)))
which gets close, but I don't feel like appending 0 to the differenced vector is the right way to go. Using findInterval didn't work either.
split(x, cumsum(c(TRUE, diff(x)!=1)))
#$`1`
#[1] 7
#
#$`2`
#[1] 1 2 3 4
#
#$`3`
#[1] 6 7
#
#$`4`
#[1] 9
Just for fun, you can make use of Carl Witthoft's seqle function from his "cgwtools" package. (It's not going to be anywhere near as efficient as Roland's answer.)
library(cgwtools)
## Here's what seqle does...
## It's like rle, but for sequences
seqle(x)
# Run Length Encoding
# lengths: int [1:4] 1 4 2 1
# values : num [1:4] 7 1 6 9
y <- seqle(x)
split(x, rep(seq_along(y$lengths), y$lengths))
# $`1`
# [1] 7
#
# $`2`
# [1] 1 2 3 4
#
# $`3`
# [1] 6 7
#
# $`4`
# [1] 9

X value of each element in list

how do I get the x value of each element in the list.
example:
list1 <- list(1:3,4:6)
list1
#[[1]]
#[1] 1 2 3
#
#[[2]]
#[1] 4 5 6
Imaginary function I'm looking for:
function(list1, 1)
# [1] 1 4
function(list2, 2)
# [1] 2 5
How can I do this?
Use sapply or lapply, in combination with the [ extraction function (see ?Extract for more info) like so:
> sapply(list1,"[",1)
[1] 1 4
...or with a list output:
> lapply(list1,"[",1)
[[1]]
[1] 1
[[2]]
[1] 4

Resources