How do I easily generate this sequence?
c(1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,
2,3,2,4,2,5,2,6,2,7,2,8,2,9,2,10)
Is there any simple way to write this?
How do I easily generate this sequence?
c(1,2,1,3,1,4,1,5,1,6,1,7,1,8,1,9,1,10,
2,3,2,4,2,5,2,6,2,7,2,8,2,9,2,10)
Is there any simple way to write this?
I think you want something like
t(combn(1:10, 2))
# [,1] [,2]
# [1,] 1 2
# [2,] 1 3
# [3,] 1 4
# [4,] 1 5
# [5,] 1 6
# [6,] 1 7
# [7,] 1 8
# [8,] 1 9
# [9,] 1 10
# [10,] 2 3
# [11,] 2 4
# [12,] 2 5
# [13,] 2 6
# [14,] 2 7
# [15,] 2 8
# [16,] 2 9
# [17,] 2 10
# etc
As data frame
as.data.frame(t(combn(1:10, 2)))
Here's a partially-dplyr
solution. (Of course it would be trivial to use a replacement for filter()
and not use the pipes...) expand.grid
normally works well for this, but in this case it's a little more complicated than CPak's use of combn
because we have to switch the column order:
expand.grid(1:10, 1:10) %>% rev %>% filter(Var2 < Var1) %>% t %>% as.vector
[1] 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 2 3 2 4 2 5 2 6 2
[28] 7 2 8 2 9 2 10 3 4 3 5 3 6 3 7 3 8 3 9 3 10 4 5 4 6 4 7
[55] 4 8 4 9 4 10 5 6 5 7 5 8 5 9 5 10 6 7 6 8 6 9 6 10 7 8 7
[82] 9 7 10 8 9 8 10 9 10
Adding a base
method:
n = 10
unlist(lapply(1:(n - 1), FUN = function(x) as.vector(rbind(x, (x + 1):n))))
For large n, I would expect this to be quite a bit faster as it doesn't use data frames at all and doesn't generate unneeded combinations and then filter them out.
Here is a base R
way.
fun <- function(x, k) c(k, x)
n <- 10
res <- lapply(seq_len(n - 1), function(k) sapply((k + 1):n, fun, k))
unlist(lapply(res, c))
# [1] 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 2 3 2 4 2 5 2
#[26] 6 2 7 2 8 2 9 2 10 3 4 3 5 3 6 3 7 3 8 3 9 3 10 4 5
#[51] 4 6 4 7 4 8 4 9 4 10 5 6 5 7 5 8 5 9 5 10 6 7 6 8 6
#[76] 9 6 10 7 8 7 9 7 10 8 9 8 10 9 10
Here is a little function using base R that allows you to control the starting and stopping values.
combos <- function(x, y) unlist(Map(rbind, as.list(1:x), lapply(2:(x+1), ":", y)))
combos(3, 10)
[1] 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 2 3 2 4 2 5 2 6 2
[28] 7 2 8 2 9 2 10 3 4 3 5 3 6 3 7 3 8 3 9 3 10
combos(2, 5)
[1] 1 2 1 3 1 4 1 5 2 3 2 4 2 5
combos(3, 5)
[1] 1 2 1 3 1 4 1 5 2 3 2 4 2 5 3 4 3 5
Here is an option using dplyr
and tidyr
. result
is the final output. You may want to further subset the result
vector or subset the df2
for your needs. After seeing Gregor's answer, I think my original approach is too complicated and thus I updated the approach as follows.
library(dplyr)
library(tidyr)
dt <- data.frame(a = 1:10, b = 1:10)
dt2 <- dt %>%
complete(a, b) %>%
filter(b > a)
result <- dt2 %>%
t() %>%
as.vector()
result
[1] 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 2 3 2 4 2 5 2 6 2
[28] 7 2 8 2 9 2 10 3 4 3 5 3 6 3 7 3 8 3 9 3 10 4 5 4 6 4 7
[55] 4 8 4 9 4 10 5 6 5 7 5 8 5 9 5 10 6 7 6 8 6 9 6 10 7 8 7
[82] 9 7 10 8 9 8 10 9 10
Because row is sorted based on column a
, you can filter the column a
based on the number you need. For example, if you only want the first number no bigger than 2. You can do the following for your df2
dt2 <- dt %>%
complete(a, b) %>%
filter(b > a) %>%
filter(a < 3)
Using df2
for the same code to generate result
as mentioned above, you will get the same desired output as your example.
I used a for loop. If you want a long sequence, this will not be your best choice:
# Create vectors for desired sequence
x <- 1:10
y <- 1:2
# Initiate sequence vector
seq <- c()
# Loop to fill in sequence vector
for(elem in y){
for(i in 1:length(x)){
toappend <- c(elem, x[i])
seq <- c(seq, toappend)
}
}
> print(seq)
[1] 1 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 2 1 2 2 2 3 2 4 2
[30] 5 2 6 2 7 2 8 2 9 2 10