0

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?

KenHBS
  • 6,756
  • 6
  • 37
  • 52
Haakonkas
  • 961
  • 9
  • 26
  • 3
    Do you want it to continue logically, i.e., `3, 4, 3, 5, 3, 6, ...` or are you happy with the length you have? The `df %>% slice` seems unrelated to your question (especially since you don't provide `df`). I think your question would be clearer if it was just "how do I generate this sequence?" – Gregor Thomas Oct 02 '17 at 20:15
  • Thanks for feedback, i edited the question. – Haakonkas Oct 02 '17 at 20:17
  • I want it to continue logically yes, at least for the length of my data frame – Haakonkas Oct 02 '17 at 20:18

6 Answers6

6

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)))
CPak
  • 13,260
  • 3
  • 30
  • 48
5

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.

Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
  • Thank you! This was a quick and simple solution, worked perfectly! – Haakonkas Oct 02 '17 at 20:53
  • Could you elaborate what the %>% t %>% as.vector does? Converts it to a list, then to a vector? – Haakonkas Oct 02 '17 at 21:11
  • `?t` is the transpose so that its in the order you want (R uses column major order by default). And then `as.vector` makes it a 1-dimensional instead of a matrix. Try without the `t` and see what it looks like (maybe with n = 3). Feel free to experiment - you'll understand much better than my explanation. – Gregor Thomas Oct 02 '17 at 21:15
3

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
Rui Barradas
  • 70,273
  • 8
  • 34
  • 66
2

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
lmo
  • 37,904
  • 9
  • 56
  • 69
1

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.

www
  • 38,575
  • 12
  • 48
  • 84
0

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
Agarp
  • 433
  • 7
  • 15