No sé cómo se llama, ¿quizás progresión aritmética anidada? Si n es un número entero, digamos n = 50, lo que me gustaría es

 (1,2,3...n,2,3...n,3,4..n...n-1,n)

Es como una concatenación de

 1:n, 2:n, ...,n-1:n

¿Hay una manera fácil de hacer esto? ¡Gracias!

r
1
Ben Z 13 sep. 2018 a las 05:36

3 respuestas

La mejor respuesta

El sujeto dice que la última subsecuencia es n pero el cuerpo de la pregunta dice que es (n-1):n. He asumido (n-1):n pero para obtener el otro simplemente cambie cada n-1 en el código a n y cada 2 en el código a 1.

1) lapply Suponiendo que queremos 1: n, 2: n, ..., (n-1): n iterar sobre el valor inicial de cada subsecuencia de esta manera:

n <- 4
unlist(lapply(seq_len(n-1), seq, n))
##  [1] 1 2 3 4 2 3 4 3 4

2) secuencia Otro enfoque es transformar sequence(seq(n, 2)) de esta manera:

s <- sequence(seq(n, 2))
s + cumsum(s == 1) - 1
## [1] 1 2 3 4 2 3 4 3 4

3) exterior

m <- outer(seq_len(n), seq_len(n-1), ">=") * seq(n)
m[m > 0]
## [1] 1 2 3 4 2 3 4 3 4

3a) Esta variación de (3) también funciona:

m <- outer(seq_len(n), seq_len(n-1), "+") - 1
m[m <= n]
## [1] 1 2 3 4 2 3 4 3 4

4) Reducir

f <- function(x, y) c(x, seq(y, n))
Reduce(f, 1:(n-1), c())
## [1] 1 2 3 4 2 3 4 3 4

5) Recursión

Recurse <- function(v) {
  if (length(v) > 2) c(v, Recall(tail(v, -1))) else v
}
Recurse(1:n)
## [1] 1 2 3 4 2 3 4 3 4
8
G. Grothendieck 13 sep. 2018 a las 03:54

Por ejemplo,

> n <- 4
> X <- matrix(1:n, nrow = n, ncol = n)
> X
     [,1] [,2] [,3] [,4]
[1,]    1    1    1    1
[2,]    2    2    2    2
[3,]    3    3    3    3
[4,]    4    4    4    4
> lower.tri(X, diag = TRUE)
     [,1]  [,2]  [,3]  [,4]
[1,] TRUE FALSE FALSE FALSE
[2,] TRUE  TRUE FALSE FALSE
[3,] TRUE  TRUE  TRUE FALSE
[4,] TRUE  TRUE  TRUE  TRUE
> x <- X[lower.tri(X, diag = TRUE)]
> x
 [1] 1 2 3 4 2 3 4 3 4 4
> x[-length(x)]
[1] 1 2 3 4 2 3 4 3 4
0
HenrikB 13 sep. 2018 a las 02:42

Usando Rcpp

library(Rcpp)

cppFunction('Rcpp::NumericVector mySeq( int n ) {
  Rcpp::IntegerVector vec = seq(0, n);
  int total_n = sum( vec );
  Rcpp::NumericVector out(total_n);

  size_t i, j;
  int idx = 0;
  int x = 1;
  for( i = 0; i < n; i++ ) {
    x = i + 1;
    for( j = i; j < n; j++) {
      out[idx] = x;
      x++;
      idx++;
    }
  }
  return out;
}')

mySeq(5)
#  [1] 1 2 3 4 5 2 3 4 5 3 4 5 4 5 5

mySeq(10)
# [1]  1  2  3  4  5  6  7  8  9 10  2  3  4  5  6  7  8  9 10  3  4  5  6  7  8  9 10  4  5  6  7  8  9 10  5  6  7  8
# [39]  9 10  6  7  8  9 10  7  8  9 10  8  9 10  9 10 10

Y como siempre con estas respuestas de opciones múltiples, aquí hay un punto de referencia

library(microbenchmark)

n <- 10000

microbenchmark(
  rcpp = { mySeq(n) },
  lapply = { lapn(n) },
  sequence = { seqn(n) },
  outer = { outn(n) },
  outer2 = { outn2(n) },
  # reduce = { reducen(n) },   ## takes too long
  # recurse = { recursen(n) }, ## takes too long
  times = 10
)

# Unit: milliseconds
#     expr       min        lq      mean    median        uq       max neval
#     rcpp  213.9762  220.3786  245.6753  230.6847  262.8544  326.5764    10
#   lapply  250.5695  260.5681  288.2523  278.9582  302.9768  367.5507    10
# sequence 1356.2691 1430.5877 1472.6946 1455.7467 1485.3578 1753.4076    10
#    outer 2381.8864 2459.8159 2497.1630 2478.9865 2526.9577 2662.0489    10
#   outer2 2509.8079 2531.1497 2651.6906 2636.3873 2785.3693 2820.2356    10

Las funciones

lapn <- function(n) { unlist(lapply(seq_len(n-1), seq, n)) }

seqn <- function(n) {
  s <- sequence(seq(n, 2))
  s + cumsum(s == 1) - 1
  return(s)
}
outn <- function(n) {
  m <- outer(seq_len(n), seq_len(n-1), ">=") * seq(n)
  m[m > 0]
}
outn2 <- function(n) {
  m <- outer(seq_len(n), seq_len(n-1), "+") - 1
  m[m <= n]
}
reducen <- function(n) {
  f <- function(x, y) c(x, seq(y, n))
  Reduce(f, 1:(n-1), c())
}
recursen <- function(n) {
  Recurse <- function(v) {
    if (length(v) > 2) c(v, Recall(tail(v, -1))) else v
  }
  Recurse(1:n)
}
2
SymbolixAU 13 sep. 2018 a las 04:30