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