2015-10-05 2 views
-2

Начиная с вектора, я хочу удалить элементы, чтобы остальные элементы увеличивались. У меня уже есть итеративный подход, который идет следующим образом:Создать увеличивающий вектор

test<- c(2,4,7,2,3,6,8) 
while(!all(diff(test)>=0)){ 
    rm <- which(diff(test)<0)[1]+1 
    if(!is.na(rm)) test<-test[-rm] 
} 

Ожидаемый результат в моем примере будет (2,4,7,8).

Есть ли более разумный способ сделать это?

EDIT: Добавлен ожидаемый выход алгоритма.

EDIT: Typo выхода.

EDIT: Исправлен мой код, чтобы он дал желаемый результат.

EDIT: Изменен пример с более общим, добавив 8 в конец.

+0

Проблема, о которой вы говорите, не определена. Может быть (2,4,7), может быть (2,3,6) и так далее. – tonytonov

+0

Каков ваш желаемый результат? Я бы подумал «c (2,4,7)», но ваш код предлагает что-то другое. И мне непонятно, что вы хотите, если, скажем, 'test <- c (2,4,7,2,3,6,9)'. – ulfelder

+1

вывод, который дает код: 'c (2, 2, 3, 6)' – Cath

ответ

0

Я хотел бы поблагодарить всех, кто участвовал в этой дискуссии я использовал код digEmAll в для сравнительного анализа и сопоставляются все методы выше. Вот результаты.

makeIncreasing_digEmAll <- function(test){ 
     test2 <- rep(NA,length(test)) 
     test2[1] <- test[1] 
     prev <- test[1] 
     for(i in 2:length(test)){ 
       if(prev < test[i]){ 
         test2[i] <- test[i] 
         prev <- test[i] 
       } 
     } 
     test2 <- test2[!is.na(test2)] 
     return(test2) 
} 

makeIncreasing_Jcl <- function(test){ 
     while(!all(diff(test)>=0)){ 
       rm <- which(diff(test)<0)[1]+1 
       if(!is.na(rm)) test<-test[-rm] 
     } 
     return(test) 
} 

makeIncreasing_Jcl2 <- function(test){ 

     return(unique(cumsum(test))) 
} 

makeIncreasing_CathG <- function(test){ 
     last_val <- test[1] 
     out_ind <- c(1) 
     i <- 2 
     while (i<=length(test)){ 
       if (test[i] >= last_val) {out_ind <- c(out_ind, i); last_val <- test[i]} 
       i <- i+1 
     } 
     return(test) 
} 

set.seed(123) 
test2 <- runif(n=1000,min=1,max=10000) 

timeDigEmAll <- system.time(for(i in 1:200)makeIncreasing_digEmAll(test2),gcFirst=T) 
timeJcl <- system.time(for(i in 1:200)makeIncreasing_Jcl(test2),gcFirst=T) 
timeJcl2 <- system.time(for(i in 1:200)makeIncreasing_Jcl2(test2),gcFirst=T) 
timeCathG <- system.time(for(i in 1:200)makeIncreasing_CathG(test2),gcFirst=T) 



> timeDigEmAll 
    user system elapsed 
    0.068 0.000 0.068 
> timeJcl 
    user system elapsed 
    14.64 0.00 14.64 
> timeJcl2 
    user system elapsed 
    0.008 0.000 0.008 
> timeCathG 
    user system elapsed 
    0.124 0.000 0.124 

В заключение unique(cumsum(test)) это путь.

4

Может быть, это помогает:

test[1:which(diff(test) < 0)] 
#[1] 2 4 7 
+2

Это не удается: 'тест <- с (2,4,7,2,3,1)' – digEmAll

+3

Это даст другой ответ на свой код, хотя. Он удалит первый не увеличивающий элемент, затем снова вернется в список, удалив следующий не увеличивающий элемент, продолжая, пока список не будет строго возрастать. Этот метод вырезает список, когда речь заходит о первом невозрастающем элементе. Поэтому его метод даст 2, 4, 6, а ваш даст 2, 4, 7. – JCollerton

+0

Приношу свои извинения, я признаю, что мой вопрос, возможно, не был достаточно ясен. Моя цель - удалить элементы, чтобы увеличить вектор. – Jonkie

5

Учитывая вывод, полученный с помощью кода, я полагаю, вы хотите, чтобы удалить значения, что делает число в вашем векторе не увеличивается.

EDIT2

Если вы хотите сохранить все возрастающие значения, вот вариант с while:

last_val <- test[1] 
out_ind <- c(1) 
i <- 2 
while (i<=length(test)){ 
    if (test[i] >= last_val) {out_ind <- c(out_ind, i); last_val <- test[i]} 
    i <- i+1 
} 

EDIT1

Если вы просто хотите, чтобы удалить номера после сначала не увеличивая его, вы можете пойти с ответом @RHertel или test[1:which(diff(test) < 0)[1]], чтобы избежать предупреждения, если есть множество es отрицательные значения «diff».

Первый ответ с ожидаемым выходом из кода

вот способ сделать это:

# get the indexes of the sorted vector 
ot <- order(test) 
# then you remove the value that doesn't correspond to increasing indexes 
test <- test[-ot[which(diff(ot)<0)+1]] 
>test 
#[1] 2 2 3 6 
+1

пожалуйста, может человек, который отклонил аргумент вниз? Я получаю вывод, заданный кодом OP, и (imo) мой код делает то, что задано. – Cath

+0

@Jcl. Кажется, это дает результат вашего цикла, который вы хотите в соответствии с вашим описанием. – LyzandeR

+0

Я заметил опечатку в моем первоначальном вопросе, я сожалею об этом. – Jonkie

1

Я хотел бы использовать старый добрый for-loop:

test <- c(2,4,7,2,3,9) 

test2 <- rep(NA,length(test)) 
test2[1] <- test[1] 
prev <- test[1] 
for(i in 2:length(test)){ 
    if(prev < test[i]){ 
    test2[i] <- test[i] 
    prev <- test[i] 
    } 
} 
test2 <- test2[!is.na(test2)] 

#> test2 
#[1] 2 4 7 9 

Контрольный показатель:

makeIncreasing_digEmAll <- function(test){ 
    test2 <- rep(NA,length(test)) 
    test2[1] <- test[1] 
    prev <- test[1] 
    for(i in 2:length(test)){ 
    if(prev < test[i]){ 
     test2[i] <- test[i] 
     prev <- test[i] 
    } 
    } 
    test2 <- test2[!is.na(test2)] 
    return(test2) 
} 

makeIncreasing_Jcl <- function(test){ 
    while(!all(diff(test)>=0)){ 
    rm <- which(diff(test)<0)[1]+1 
    if(!is.na(rm)) test<-test[-rm] 
    } 
    return(test) 
} 


set.seed(123) 
test2 <- runif(n=1000,min=1,max=10000) 

timeDigEmAll <- system.time(for(i in 1:200)makeIncreasing_digEmAll(test2),gcFirst=T) 
timeJcl <- system.time(for(i in 1:200)makeIncreasing_Jcl(test2),gcFirst=T) 

> timeDigEmAll 
    user system elapsed 
    0.17 0.00 0.17 
> timeJcl 
    user system elapsed 
    29.80 0.02 30.28 
+0

Я ценю вас за помощь. (особенно тестирование ответов выше!), но я смог сделать свой алгоритм, который использует цикл while, запустить. – Jonkie

+0

Хорошо, я предлагаю вам разместить свой собственный код в качестве ответа, так что вы можете показать нам, что ваше решение;) – digEmAll

+0

Я отредактировал мой щёток предложение в ответ. – Jonkie

2

Если вы не нуждаетесь в 2 3 3 1 4, чтобы получить 2 3 3 4 (т.е. равно не растет), вы можете использовать хороший уменьшить

test <- c(2,4,7,2,3,1,8) 
unique(Reduce(max, as.list(test), accumulate = TRUE)) 
[1] 2 4 7 8 

Если вы хотите повторы, я уверен, что есть более хороший способ сделать это, но

test <- c(2,4,4,7,2,3,1,8) 
reduce = Reduce(max, as.list(test), accumulate = TRUE) 
df = data.frame(o = test, reduce = reduce) 
df[df$o == df$reduce, "o"] 
[1] 2 4 4 7 8 

потянет их.

+0

Это замечательно! Я на самом деле не функциональный программист, поэтому я даже не думал об уменьшении, но это определенно путь. +1 – digEmAll

+1

Привет, спасибо за ваш ответ я нашел еще один способ сделать это, которая в основном сводится к тому, вашему методу, который является уникальным '(cummax (тест))' – Jonkie

+0

О удивительным! Гораздо лучше, чем у меня, и, по-видимому, он определен для матриц и фреймов. –

Смежные вопросы