Подтвердить что ты не робот

Генерировать ряды 1,2,1,3,2,1,4,3,2,1,5,4,3,2,1

Я пытаюсь создать вектор, содержащий возрастающий обратный ряд, такой как 1,2,1,3,2,1,4,3,2,1,5,4,3,2,1.

Я попытался использовать цикл для этого, но я не знаю, как складывать или конкатенировать результаты.

for (i in 1:11)
 {
 x = rev(seq(i:1))
 print(x) 
 }
[1] 1
[1] 2 1
[1] 3 2 1
[1] 4 3 2 1
[1] 5 4 3 2 1
[1] 6 5 4 3 2 1
[1] 7 6 5 4 3 2 1
[1] 8 7 6 5 4 3 2 1
[1] 9 8 7 6 5 4 3 2 1
[1] 10  9  8  7  6  5  4  3  2  1
[1] 11 10  9  8  7  6  5  4  3  2  1

Я также экспериментировал с rep, rev и seq, которые являются моим любимым вариантом, но не получили далеко.

4b9b3361

Ответ 1

С sequence:

rev(sequence(5:1))
# [1] 1 2 1 3 2 1 4 3 2 1 5 4 3 2 1

Ответ 2

Мы можем сделать это с помощью lapply

unlist(lapply(1:11, function(x) rev(seq(x))))

Или как @zx8754, упомянутое в комментариях, вместо rev(seq, : можно использовать

unlist(lapply(1:11, function(x) x:1))

Или, как предположил @BrodieG, мы можем сделать это более компактным, удалив анонимный вызов функции

unlist(lapply(1:11, ":", 1))

Ответ 3

И для удовольствия, используя матрицы (и игнорируя предупреждение;))

m <- matrix(c(1:5,0), ncol = 5, nrow = 5, byrow = T)
m[ upper.tri(m, diag = T) ]
# [1] 1 2 1 3 2 1 4 3 2 1 5 4 3 2 1

И мы можем упростить upper.tri в его составные части

m[ row(m) <= col(m)]
# [1] 1 2 1 3 2 1 4 3 2 1 5 4 3 2 1

И если вы справитесь с еще большим удовольствием, то как насчет некоторого бенчмаркинга:

library(microbenchmark)
maxValue <- 1000

vec2 <- maxValue:1
m2 <- matrix(c(1:maxValue,0), ncol = maxValue, nrow = maxValue, byrow = T)

microbenchmark(

    henrik = {
        rev(sequence(maxValue:1))
    },
    akrun = {
        unlist(lapply(1:maxValue, function(x) x:1))
    },
    symbolix1 = {
        m <- matrix(c(1:maxValue,0), ncol = maxValue, nrow = maxValue, byrow = T)
        m[ row(m) <= col(m) ]
    },
    symbolix2 = {
        m2[ row(m2) <= col(m2) ]
    },
    lmo1 = {
        unlist(lapply(1:maxValue, tail, x=maxValue:1))
    },
    lmo2 = {
        vec <- maxValue:1
        unlist(lapply(rev(vec), tail, x=vec))
    },
    lmo3 = {
        unlist(lapply(rev(vec2), tail, x=vec2))
    }
)

# Unit: milliseconds
#      expr       min        lq      mean    median        uq      max neval
#    henrik  3.342175  4.095287  5.185095  4.960354  5.703463 32.08644   100
#     akrun  1.535998  1.761439  2.159954  2.162721  2.292743 10.80862   100
# symbolix1 13.443495 15.145713 16.588118 17.145578 17.896521 20.81460   100
# symbolix2  8.640927 10.245634 11.656378 12.297788 12.791973 14.39691   100
#      lmo1 13.124813 14.301375 17.253844 14.795471 15.718820 61.09737   100
#      lmo2 13.026593 14.202633 18.042158 14.891164 17.729049 86.18921   100
#      lmo3 13.355810 14.424353 18.497383 14.876103 20.100575 76.96622   100

В этом примере победителем будет akrun (и zx8754 по прокси)!


Но я знаю, о чем вы думаете, "зачем заканчивать все там весело!"

Хорошо, давайте напишем нашу собственную функцию С++ и посмотрим, как это работает

library(Rcpp)

cppFunction('NumericVector reverseSequence(int maxValue, int vectorLength){

                        NumericVector out(vectorLength);
                        int counter = 0;

                        for(int i = 1; i <= maxValue; i++){
                            for(int j = i; j > 0; j--){
                                out[counter] = j;
                                counter++;
                            }
                        }

                        return out;
                        }')

maxValue <- 5
reverseSequence(maxValue, sum(1:maxValue))
 [1] 1 2 1 3 2 1 4 3 2 1 5 4 3 2 1

library(microbenchmark)
maxValue <- 1000

microbenchmark(
    akrun = {
        unlist(sapply(1:maxValue, function(x) x:1))
    },
    symbolix3 = {
        reverseSequence(maxValue, sum(1:maxValue))
    }
)

# Unit: microseconds
#        expr      min        lq     mean    median       uq       max neval
#      akrun 1522.250 1631.6030 3148.922 1829.9370 3357.493 45576.148   100
#  symbolix3  338.626  495.3825 1293.720  950.6635 2169.656  3816.091   100

Ответ 4

Другой альтернативой является использование tail внутри lapply для последовательного выбора количества элементов, которые нужно сохранить от исходного вектора:

unlist(lapply(1:5, tail, x=5:1))
 [1] 1 2 1 3 2 1 4 3 2 1 5 4 3 2 1

Или, возможно, быстрее сначала построить базовый вектор, а затем вызвать его:

vec <- 5:1
unlist(lapply(rev(vec), tail, x=vec))
 [1] 1 2 1 3 2 1 4 3 2 1 5 4 3 2 1