У меня есть задача вроде
n <- 5
set.seed(11)
X <- rnorm(n)
X.sort <- {}
for(i in 1:n){
X.sort <- sort.int(c(X.sort, X[i]), decreasing = TRUE)
print(X.sort) # actually, other computations with X.sort
}
, что приводит к выводу вида
[1] -0.5910311
[1] 0.02659437 -0.59103110
[1] 0.02659437 -0.59103110 -1.51655310
[1] 0.02659437 -0.59103110 -1.36265335 -1.51655310
[1] 1.17848916 0.02659437 -0.59103110 -1.36265335 -1.51655310
Мне кажется неэффективным «пересортировать» X.sort
в каждом раунде цикла, когда вектор уже отсортирован, за исключением новой записи X[i]
, которая должна быть вставлена.
Я пытался "сказать" R, куда вставить элемент через
library(R.utils)
X.sort <- {}
for(i in 1:n){
pos <- match(F, X.sort>X[i])
if(is.na(pos)){
X.sort <- c(X.sort,X[i])
} else {
X.sort <- insert(X.sort, pos, X[i])
}
print(X.sort)
}
но это не дает никакой выгоды при тестировании.
Есть очевидное улучшение или R уже эффективно использует знание, что X.sort
отсортирован?
EDIT:
Бенчмаркинг предлагает [НО ПОЖАЛУЙСТА, ТАКЖЕ РАССМОТРЕТЬ ОТВЕТЫ НИЖЕ] принятого ответа, чтобы быть самым быстрым (по крайней мере, когда n
приближается к 1000), что, к тому же, кажется, также работает для больших n
и является самым простым один.
library(R.utils)
library(microbenchmark)
n <- 600
set.seed(11)
X <- rnorm(n)
sorted_insert <- function(x, y) {
c(x[x >= y], y, x[x < y])
}
recursive_fun <- function(ans=list(NULL), vec, i=1) {
if (i > length(vec)) {
tail(ans, -1)
} else {
ans <- c(ans, list(sorted_insert(ans[[i]], vec[i])))
recursive_fun(ans=ans, vec, i=i+1)
}
}
microbenchmark(
{
X.sort <- {}
for(i in 1:n){
X.sort <- sort.int(c(X.sort, X[i]), decreasing = TRUE)
}
},{
X.sort <- {}
for(i in 1:n){
pos <- match(F, X.sort>X[i])
if(is.na(pos)){
X.sort <- c(X.sort,X[i])
} else {
X.sort <- insert(X.sort, pos, X[i])
}
}
},{
X.sort <- {X[1]}
for(i in 2:n){
X.sort <- append(X.sort, X[i], after = sum(X.sort > X[i]))
}
},{
lapply(seq_along(X), function(a) {sort(X[seq_len(a)], decreasing = T)})
},{
lapply(1:length(X), function(i) sort(X[1:i], decreasing = T))
},
{
recursive_fun(vec=X)
},
times=50
)
Результат:
min lq mean median uq max neval
21.308012 22.264314 24.065012 22.798643 26.381362 34.629395 50
19.554413 20.334643 21.875769 20.617807 24.085896 30.625841 50
4.497919 4.804550 5.380192 4.912923 5.114310 13.522485 50
23.540616 24.105807 25.311692 24.335780 24.985024 30.348792 50
23.251905 24.067122 25.722031 24.745380 27.986197 30.010018 50
3.928746 4.096568 4.358911 4.258701 4.390684 9.106202 50