Fill array in for-loop with sequences of different lengths [duplicate] - r

This question already has answers here:
Generate a sequence of numbers with repeated intervals
(6 answers)
Closed 5 years ago.
I've got some struggle with a small issue. What I want to get is a dim=1 array to be filled up with help of this for-loop.
Minimal-Example (it's not working!):
Numbers <- seq(1,5)
Result <- array(NA)
for(n in Numbers){
Result[n] <- seq(n,5)
# The Result array should be like this:
# (1, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5)
}
I guess there a two problems:
The Result[n] don't have the same length
The index n in Result[n] is wrong. Actually, it should be dynamic, thus, change with every new n.
Can you guys help me?
Thank you!

We can do this with sapply
unlist(sapply(Numbers, function(x) seq(x, 5)))
#[1] 1 2 3 4 5 2 3 4 5 3 4 5 4 5 5
Or using the for loop
Result <- c()
for(n in Numbers){
Result <- c(Result, seq(n, 5))
}
Result
#[1] 1 2 3 4 5 2 3 4 5 3 4 5 4 5 5

Using sequence and rep:
n <- 5
sequence(n:1) + rep(0:(n-1), n:1)
# [1] 1 2 3 4 5 2 3 4 5 3 4 5 4 5 5
You may also create an 'oversized' matrix and select the lower triangle:
m <- matrix(c(NA, 1:n), nrow = n + 1, ncol = n + 1)
m[lower.tri(m)]
# [1] 1 2 3 4 5 2 3 4 5 3 4 5 4 5 5

Related

How to split the data 1 1 2 2 3 3 to 1 2 3 1 2 3 in R? [duplicate]

This question already has an answer here:
Sort vector into repeating sequence when sequential values are missing R
(1 answer)
Closed 6 months ago.
I want to convert a vector:
1 1 2 2 3 3
to
1 2 3 1 2 3
How to do it? Many thanks.
You can use a matrix to layout the original vector by rows and then convert it back to a vector to get the desired result.
v = c(1,1,2,2,3,3)
v2 = as.vector(matrix(v, nrow = length(unique(v)), byrow = T))
> v2
[1] 1 2 3 1 2 3
The length(unique(v)) is there to generalize how many rows the matrix should have and not hardcode a 3.
Another example:
v = c(1,1,1,2,2,2,3,3,3,4,4,4)
v2 = as.vector(matrix(v, nrow = length(unique(v)), byrow = T))
v2
[1] 1 2 3 4 1 2 3 4 1 2 3 4
We can use rbind/split
c(do.call(rbind, split(v1, v1)))
#[1] 1 2 3 1 2 3
Or if there are unequal number of replications of each element, get the order of the rowid
library(data.table)
v1[order(rowid(v1))]
#[1] 1 2 3 1 2 3
Or with base R
v1[order(ave(v1, v1, FUN = seq_along))]
#[1] 1 2 3 1 2 3
data
v1 <- c(1, 1, 2, 2, 3, 3)
vec <- c(1, 1, 2, 2, 3, 3)
rep(unique(vec), 2)
[1] 1 2 3 1 2 3

How do you efficiently return the order of an increasing index? [duplicate]

This question already has answers here:
Create group names for consecutive values
(4 answers)
Closed 4 years ago.
I have the following index vector:
TestVec = rep(c(6,8,9,11,18), each = 10)
This reads c(6, 6, ..., 6, 8, 8, ..., 8, 9, 9, ..., 9, ...).
I would like to convert this vector into c(1, 1, ..., 1, 2, 2, ..., 2, 3, 3, ..., 3, ...)
Try
I have improvised a quick-and-dirty method, as follows:
sapply(TestVec, function(x) {which(x == unique(TestVec))})
This works fine, but this takes a lot of time in a large dataset.
Is there any efficient way to improve?
match(TestVec, unique(TestVec))
Another option:
as.numeric(as.factor(TestVec))
# [1] 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5
Requiring data.table:
rleid(TestVec)
Here is another one,
c(1, cumsum(diff(TestVec) != 0)) + 1

How do I duplicate values in R? [duplicate]

This question already has answers here:
Create sequence of repeated values, in sequence?
(3 answers)
Closed 4 years ago.
Assume I have the following vector:
v1 <- c(1, 2, 3, 4, 5)
If I wanted to expand this vector so that there are 50 1 values, 50 2 values, etc., how would I do this?
Please let me know if you need any clarification.
Have a look at this:
v1 <- c(1, 2, 3, 4, 5)
rep(v1, 2)
# [1] 1 2 3 4 5 1 2 3 4 5
Or with each (after #Rui's comment):
rep(v1, each = 2)
# [1] 1 1 2 2 3 3 4 4 5 5

How to count entries with specific values in R [duplicate]

This question already has an answer here:
Include levels of zero count in result of table()
(1 answer)
Closed 6 years ago.
Let's say I have two vectors
x <- c(1, 2, 2, 3, 4, 4, 5, 5, 5)
y <- c(3, 3, 3, 4, 5, 6, 6, 7, 7)
The unique numbers among all the numbers in these vectors are 1:7. I know that if I use the table function in R, I can count the number of unique entries in each of the vectors. For example, if I apply the table function to the first vector, I will get
table(x)
#x
# 1 2 3 4 5
# 1 2 1 2 3
Applying it to the second vector, I will get
table(y)
# y
# 3 4 5 6 7
# 3 1 1 2 2
How can I get it to count the number of occurrences of all unique entries in both vectors? For example, I'd like to produce the following results:
1 2 3 4 5 6 7
1 2 1 2 3 0 0
for the first vector and
1 2 3 4 5 6 7
0 0 3 1 1 2 2
First, generate a list of the values you want to get counts for in both vectors
lvl<-unique(c(x,y))
Then explicitly list those values as levels of a factor before doing table
table(factor(x, lvl))
table(factor(y, lvl))
table(factor(x, unique(union(x,y))))
table(factor(y, unique(union(x,y))))

Wrap around subtraction

I have these numbers:
login.day$wday
[1] 5 6 7 1 2 3 4
and I want to map them to:
login.day$wday
[1] 4 5 6 7 1 2 3
Each number is subtracted by 1, and if the answer is 0, wrap it around back to 7. This is embarrassingly simple but I just can't figure it out. My attempt keeps giving me a zero:
> (login.day$wday + 6) %% 7
[1] 4 5 6 0 1 2 3
Prefer solution in R. Is it possible to do with modulo arithmetic or must I use an if statement?
Mathematically equivalent to the other solution, and with some explanation.
(login.day$wday - 1 - 1) %% 7 + 1
The problem is that it is hard to do modular arithmetic with numbers starting at 1.
We start by doing -1 to shift everything down by 1, so we have a zero-based numbers ranging from [0,6].
We then subtract 1, because that is what we were trying to do to begin with.
Next, we take the modulus, and add 1 back to shift everything back up to the range [1,7].
(login.day$wday + 5) %% 7 + 1
perhaps?
The boundary conditions are 7 -> 6, 1 -> 7 and 2 -> 1.
The result had to involve %% 7 as you so rightly spotted.
And since the last of these boundary conditions results in 1, then we need to add 1 after doing the modulo, and reduce the number added before the modulo by 1.
I have a silly function I've written called shift that does this:
shift <- function(x = 1:10, n = 1) {
if (n == 0) x <- x
else x <- c(tail(x, -n), head(x, n))
x
}
x <- c(5, 6, 7, 1, 2, 3, 4)
shift(x, -1)
# [1] 4 5 6 7 1 2 3
shift(x, -2)
# [1] 3 4 5 6 7 1 2
The use I had in mind for this was something like the following:
set.seed(1)
X <- sample(7, 20, TRUE)
X
# [1] 2 3 5 7 2 7 7 5 5 1 2 2 5 3 6 4 6 7 3 6
shift(sort(unique(X)), -1)[X]
# [1] 1 2 4 6 1 6 6 4 4 7 1 1 4 2 5 3 5 6 2 5
I like the solution of #merlin2011 but just to add to the options here is a lookup table approach:
c(7, 1:6)[login.day$wday]

Resources