Ответ 1
С sequence
:
rev(sequence(5:1))
# [1] 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
, которые являются моим любимым вариантом, но не получили далеко.
С sequence
:
rev(sequence(5:1))
# [1] 1 2 1 3 2 1 4 3 2 1 5 4 3 2 1
Мы можем сделать это с помощью 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))
И для удовольствия, используя матрицы (и игнорируя предупреждение;))
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
Другой альтернативой является использование 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