Combine vectors of list in R - r

I have a list contains number of vectors with different length as below:
lst <- list(c(1,2), c(1,2), c(4,5,10,11,12,13), c(7,8,9))
lst
[[1]]
[1] 1 2
[[2]]
[1] 1 2
[[3]]
[1] 4 5 10 11 12 13
[[4]]
[1] 7 8 9
[[5]]
[1] 7 8 9
how can I combine and remove repeated vectors to be similar to the list below:
[[1]]
[1] 1 2
[[2]]
[1] 4 5 10 11 12 13
[[3]]
[1] 7 8 9
for repeated vectors I can use unique function.

Here is one option. We unlist the list, get a logical vector with duplicated, relist it to a list having the same skeleton as the original list, subset the 'l1' based on the logical list with Map and Filter out the list elements having 0 elements.
Filter(length, Map(`[`, l1, relist(!duplicated(unlist(l1)), skeleton = l1)))
#[[1]]
#[1] 1 2
#[[2]]
#[1] 4 5 10 11 12 13
#[[3]]
#[1] 7 8 9
#[[4]]
#[1] 14 15
#[[5]]
#[1] 19 20
data
l1 <- list(1:2, 1:2, c(4, 5, 10, 11, 12, 13), 7:9, 7:9, 10:13, 10:13,
c(4, 10, 11, 12, 13), 14:15, 19:20)

I have edited your answer to give a reproducible example. Please let me know if this does not correctly illustrate your problem anymore. If it does, this is trivial:
unique(lst)

Related

How to mutate str_locate_all into single list containing all positions involved in pattern

I am not able to "deconvolute" str_locate_all output so as to get all indexes involved in the pattern (not just start and end).
Here is the type of str_locate_all() output I get:
[1]]
start end
[1,] 4 7
[[2]]
start end
[1,] 8 12
[2,] 30 33
and how I would like to mutate it:
[[1]]
[1] 4 5 6 7
[[2]]
[1] 8 9 10 11 12 30 31 32 33
Thanks in advance !
You can iterate through the list, and then iterate through each row to create the sequence.
x <- list(matrix(c(4, 7), ncol = 2, dimnames = list(NULL, c("start", "end"))),
matrix(c(8, 30, 12, 33), ncol = 2, dimnames = list(NULL, c("start", "end"))))
Here it is done in base R.
lapply(x,
function(y) unlist(apply(y, 1,
function(z) seq(z[1], z[2]), simplify = FALSE)))
Gives the desired result.
[[1]]
[1] 4 5 6 7
[[2]]
[1] 8 9 10 11 12 30 31 32 33

Create a rolling list in R

Given a vector (column of a data frame), I'd like to create a rolling vector.
l = 0:10
Would return, (with a window of 3):
[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5] ...
1) rollapply r is a 9x3 matrix each of whose rows is one of the list elements asked for and split turns that into a list of vectors. Although this gives what you asked for it may be that you just want to iterate over that list and in that case it might be easier to just replace c with whatever function you wanted to use in that iteration. e.g. rollapply(l, 3, sd)
library(zoo)
l <- 0:10 # test input
r <- rollapply(l, 3, c)
split(r, row(r))
giving:
$`1`
[1] 0 1 2
$`2`
[1] 1 2 3
$`3`
[1] 2 3 4
$`4`
[1] 3 4 5
$`5`
[1] 4 5 6
$`6`
[1] 5 6 7
$`7`
[1] 6 7 8
$`8`
[1] 7 8 9
$`9`
[1] 8 9 10
2) embed This could also be done using base R like this:
r <- embed(l, 3)[, 3:1]
split(r, row(r))
You can use the following function (I am assuming you want the values to be sorted first. If not, just remove the line of code where I am using sort()) :
roll<-function(list,window){
list<-sort(list,decreasing = FALSE)
res<-vector(mode = "list")
for(i in 1:(length(list) - window + 1)){
res[[i]]<-list[i:(i + window - 1)]
}
return(res)
}
Enter your column/list values in the argument along with the window size you want and it should give you the desired output.
For example:
test<-0:10
roll(list = test,window = 3)
This results in the following output:
[[1]]
[1] 0 1 2
[[2]]
[1] 1 2 3
[[3]]
[1] 2 3 4
[[4]]
[1] 3 4 5
[[5]]
[1] 4 5 6
[[6]]
[1] 5 6 7
[[7]]
[1] 6 7 8
[[8]]
[1] 7 8 9
[[9]]
[1] 8 9 10
You can use this function for other cases and even change the window size as per your requirements.
Hope that helps!

Getting all the combination of numbers from a list that would sum to a specific number

I have the following list of numbers (1,3,4,5,7,9,10,12,15) and I want to find out all the possible combinations of 3 numbers from this list that would sum to 20.
My research on stackoverflow has led me to this post:
Finding all possible combinations of numbers to reach a given sum
There is a solution provided by Mark which stand as follows:
subset_sum = function(numbers,target,partial=0){
if(any(is.na(partial))) return()
s = sum(partial)
if(s == target) print(sprintf("sum(%s)=%s",paste(partial[-1],collapse="+"),target))
if(s > target) return()
for( i in seq_along(numbers)){
n = numbers[i]
remaining = numbers[(i+1):length(numbers)]
subset_sum(remaining,target,c(partial,n))
}
}
However I am having a hard time trying to tweak this set of codes to match my problem. Or may be there is a simpler solution?
I want the output in R to show me the list of numbers.
Any help would be appreciated.
You can use combn function and filter to meet your criteria. I have performed below calculation in 2 steps but one can perform it in single step too.
v <- c(1,3,4,5,7,9,10,12,15)
AllComb <- combn(v, 3) #generates all combination taking 3 at a time.
PossibleComb <- AllComb[,colSums(AllComb) == 20] #filter those with sum == 20
#Result: 6 sets of 3 numbers (column-wise)
PossibleComb
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] 1 1 1 3 3 4
# [2,] 4 7 9 5 7 7
# [3,] 15 12 10 12 10 9
#
# Result in list
split(PossibleComb, col(PossibleComb))
# $`1`
# [1] 1 4 15
#
# $`2`
# [1] 1 7 12
#
# $`3`
# [1] 1 9 10
#
# $`4`
# [1] 3 5 12
#
# $`5`
# [1] 3 7 10
#
# $`6`
# [1] 4 7 9
The combn also have a FUN parameter which we can describe to output as list and then Filter the list elements based on the condition
Filter(function(x) sum(x) == 20, combn(v, 3, FUN = list))
#[[1]]
#[1] 1 4 15
#[[2]]
#[1] 1 7 12
#[[3]]
#[1] 1 9 10
#[[4]]
#[1] 3 5 12
#[[5]]
#[1] 3 7 10
#[[6]]
#[1] 4 7 9
data
v <- c(1,3,4,5,7,9,10,12,15)

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

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

Resources