Grow vector by certain length and value combinations - r

I have this vector:
a = c(4,5,6,81,82,83)
My desired result is the following:
b = c(1,2,3,4,5,6,78,79,80,81,82,83)
My logic is: There are two different sequences in a (this can be checked by using length(which(diff(a)>1))+1). Each one of them has to be extended from behind to reach the length of 1:end_of_first_seq (end_of_first_seq = a[which(diff(a)>1))[1]). Thus, in this case the length of each sequence should be 6. Each sequence must therefore grow three steps behind, so 4,5,6 becomes 1,2,3,4,5,6 and 81,82,83 becomes 78,79,80,81,82,83 while all being in the same vector.
Is there any fast way to do this? (this is a simple example, the number of sequences can be higher). It is worth mentioning all "previous" sequences are the same length (in this case, 3) and they are separated by at least two values (a case like 6,7,8,9,10,11 cannot happen). I know I can do this with loops but speed is a factor.

If all sequences have same length:
vec <- c(4,5,6,81,82,83)
LEN <- 3 # sequence length
want <- matrix(vec, ncol = LEN, byrow = TRUE)
want <- cbind(want - LEN, want)
want <- as.vector(t(want))
want
# [1] 1 2 3 4 5 6 78 79 80 81 82 83

We calculate length of each sequence and since all the sequence are of same length we can extract every nth value and create a sequence between two points in every sequence.
length_of_each_seq <- a[which.max(diff(a)>1)]
n <- 3
vals <- a[seq(n, length(a), by = n)]
c(mapply(`:`, vals - (length_of_each_seq - 1), vals))
#[1] 1 2 3 4 5 6 78 79 80 81 82 83
where vals is the end of sequence
vals
#[1] 6 83
and vals - (length_of_each_seq - 1) is from where we need to start
vals - (length_of_each_seq - 1)
#[1] 1 78

Related

Fibonacci number using Repeat loop

How could I use a repeat loop to find the biggest Fibonacci number until e.g. 1000 (so that it is less than 1000)?
I found that it is possible doing it with a while loop but how would I go around doing it with repeat?
You need to test for the condition that makes you break from repeat, otherwise it will continue cycling forever:
# Set the first two numbers of the series
x <- c(0, 1)
repeat {
# Add the last two numbers of x together and append this value to x
x <- c(x, sum(tail(x, 2)))
# Check whether the last value of x is above 1000, if so chop it off and break
if(tail(x, 1) > 1000) {
x <- head(x, -1)
break
}
}
# x now contains all the Fibonacci numbers less than 1,000
x
#> [1] 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987

Return vector from list using seq [duplicate]

I would like to create a vector in which each element is the i+6th element of another vector.
For example, in a vector of length 120 I want to create another vector of length 20 in which each element is value i, i+6, i+12, i+18... of the initial vector, i.e. I want to extract every 6th element of the original.
a <- 1:120
b <- a[seq(1, length(a), 6)]
Another trick for getting sequential pieces (beyond the seq solution already mentioned) is to use a short logical vector and use vector recycling:
foo[ c( rep(FALSE, 5), TRUE ) ]
I think you are asking two things which are not necessarily the same
I want to extract every 6th element of
the original
You can do this by indexing a sequence:
foo <- 1:120
foo[1:20*6]
I would like to create a vector in
which each element is the i+6th
element of another vector.
An easy way to do this is to supplement a logical factor with FALSEs until i+6:
foo <- 1:120
i <- 1
foo[1:(i+6)==(i+6)]
[1] 7 14 21 28 35 42 49 56 63 70 77 84 91 98 105 112 119
i <- 10
foo[1:(i+6)==(i+6)]
[1] 16 32 48 64 80 96 112
To select every nth element from any starting position in the vector
nth_element <- function(vector, starting_position, n) {
vector[seq(starting_position, length(vector), n)]
}
# E.g.
vec <- 1:12
nth_element(vec, 1, 3)
# [1] 1 4 7 10
nth_element(vec, 2, 3)
# [1] 2 5 8 11
To select every n-th element with an offset/shift of f=0,...,n-1, use
vec[mod(1:length(vec), n)==f]
Of course, you can wrap this in a nice function:
nth_element <- function(vec, interval, offset=0){
vec[mod(1:length(vec), interval)==mod(offset, interval)]
}

R expand.grid with row restrictions

I have a numeric vector x of length N and would like to create a vector of the within-set sums of all of the following sets: any possible combination of the x elements with at most M elements in each combination. I put together a slow iterative approach; what I am looking for here is a way without using any loops.
Consider the approach I have been taking, in the following example with N=5 and M=4
M <- 4
x <- 11:15
y <- as.matrix(expand.grid(rep(list(0:1), length(x))))
result <- y[rowSums(y) <= M, ] %*% x
However, as N gets large (above 22 for me), the expand.grid output becomes too big and gives an error (replace x above with x <- 11:55 to observe this). Ideally there would be an expand.grid function that permits restrictions on the rows before constructing the full matrix, which (at least for what I want) would keep the matrix size within memory limits.
Is there a way to achieve this without causing problems for large N?
Your problem has to do with the sheer amount of combinations.
What you appear to be doing is listing all different combinations of 0's and 1's in a sequence of length of x.
In your example x has length 5 and you have 2^5=32 combinations
When x has length 22 you have 2^22=4194304 combinations.
Couldn't you use a binary encoding instead?
In your case that would mean
0 stands for 00000
1 stands for 00001
2 stands for 00010
3 stands for 00011
...
It will not solve your problem completely, but you should be able to get a bit further than now.
Try this:
c(0, unlist(lapply(1:M, function(k) colSums(combn(x, k)))))
It generates the same result as with your expand.grid approach, shown below for the test data.
M <- 4
x <- 11:15
# expand.grid approach
y <- as.matrix(expand.grid(rep(list(0:1), length(x))))
result <- y[rowSums(y) <= M, ] %*% x
# combn approach
result1 <- c(0, unlist(lapply(1:M, function(k) colSums(combn(x, k)))))
all(sort(result[,1]) == sort(result1))
# [1] TRUE
This should be fast (it takes 0.227577 secs on my machine, with N=22, M=4):
x <- 1:22 # N = 22
M <- 4
c(0, unlist(lapply(1:M, function(k) colSums(combn(x, k)))))
# [1] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 3 4 5 6 7
you may want to choose the unique values of the sums with
unique(c(0, unlist(lapply(1:M, function(k) colSums(combn(x, k))))))

Create a sequence of sequences of different lengths

I have to create a sequence of large number (> 10,000) of sequences of different lengths. I only know the lengths of these sequences in a vector form.
length_v <- c(2,3,4,4,2,6,11,75...................)
Each sequence starts from 1 and moves forward in steps of 1. And in the final sequence (combined one), each sequence has to appear one after the other, they can't be jumbled up.
A small demonstrating example is below:
I have say 4 sequences of length 2, 3, 4, 6 respectively.
s1 <- seq(1, 2) # 1,2
s2 <- seq(1, 3) # 1,2,3
s3 <- seq(1, 4) # 1,2,3,4
s4 <- seq(1, 6) # 1,2,3,4,5,6
Final sequence will be
final <- c(s1,s2,s3,s4) **# the order has to be this only. No compromise here.**
I can't do this with > 10,000 sequences which would be very inefficient. Is there any simpler way of doing this?
We can use sequence
sequence(length_v)
#[1] 1 2 1 2 3 1 2 3 4 1 2 3 4 5 6
data
length_v <- c(2,3,4,6)
example:
unlist(sapply(c(2,3,4,6), seq, from=1))
so for you it will be:
unlist(sapply(length_v, seq, from=1))

Extract every nth element of a vector

I would like to create a vector in which each element is the i+6th element of another vector.
For example, in a vector of length 120 I want to create another vector of length 20 in which each element is value i, i+6, i+12, i+18... of the initial vector, i.e. I want to extract every 6th element of the original.
a <- 1:120
b <- a[seq(1, length(a), 6)]
Another trick for getting sequential pieces (beyond the seq solution already mentioned) is to use a short logical vector and use vector recycling:
foo[ c( rep(FALSE, 5), TRUE ) ]
I think you are asking two things which are not necessarily the same
I want to extract every 6th element of
the original
You can do this by indexing a sequence:
foo <- 1:120
foo[1:20*6]
I would like to create a vector in
which each element is the i+6th
element of another vector.
An easy way to do this is to supplement a logical factor with FALSEs until i+6:
foo <- 1:120
i <- 1
foo[1:(i+6)==(i+6)]
[1] 7 14 21 28 35 42 49 56 63 70 77 84 91 98 105 112 119
i <- 10
foo[1:(i+6)==(i+6)]
[1] 16 32 48 64 80 96 112
To select every nth element from any starting position in the vector
nth_element <- function(vector, starting_position, n) {
vector[seq(starting_position, length(vector), n)]
}
# E.g.
vec <- 1:12
nth_element(vec, 1, 3)
# [1] 1 4 7 10
nth_element(vec, 2, 3)
# [1] 2 5 8 11
To select every n-th element with an offset/shift of f=0,...,n-1, use
vec[mod(1:length(vec), n)==f]
Of course, you can wrap this in a nice function:
nth_element <- function(vec, interval, offset=0){
vec[mod(1:length(vec), interval)==mod(offset, interval)]
}

Resources