#r #function #while-loop #repeat
#r #функция #в то время как-цикл #повторять
Вопрос:
Я пытаюсь написать функцию, которая принимает числовой вектор в качестве входных данных и возвращает индексы более короткой версии входного вектора в соответствии с некоторыми правилами:
- (a) если все элементы идентичны, верните только индекс первого элемента; т. е. верните
1
; иначе:если НЕ все элементы идентичны, то проверьте, есть ли
special_treatment_value
среди них:- (b) если
special_treatment_value
есть, верните индексы входного вектора, за исключением индексов элементов, гдеspecial_treatment_value
они появились; иначе: - (c) если
special_treatment_value
его там нет, верните индексы входного вектора как есть, т. е.,1:length(x)
.
- (b) если
Проблема: если бы мы оказались на маршруте (b), мы могли бы столкнуться с ситуацией, в которой все векторные элементы теперь одинаковы. В таком случае мы хотели бы повторить (a) еще раз, чтобы свести к минимуму только первый элемент.
Пример
Допустим, я хочу передать через свою функцию следующие векторы:
my_vec_1 lt;- c(1, 2, 1, 2, 3) my_vec_2 lt;- c(4, 4, 4) my_vec_3 lt;- c(1, 2, 1, 4, 1) my_vec_4 lt;- c(3, 3, 3, 4)
и что:
special_treatment_value lt;- 4
Согласно моим правилам, функция должна возвращать выходные данные:
- для
my_vec_1
: он соответствует маршруту (c), и, следовательно, вывод должен быть1:5
(индексы всех) - для
my_vec_2
: он соответствует маршруту (a), и, следовательно, вывод должен быть1
(индекс первого) - для
my_vec_3
: он подходит для маршрута (b). вывод должен быть1 2 3 5
(индексы всех, кроме специальных значений) my_vec_4
демонстрирует проблему. Мой желаемый результат заключается1
в том, что сначала мы проходим маршрут (b), а затем я хочу пройти через (a). Но сейчас этого не происходит, и моя функция (см. Ниже) возвращает1 2 3
(индексы всех, кроме специальных значений).
моя нынешняя попытка
get_indexes lt;- function(x, special_val) { if (var(x) == 0) { # route (a) output_idx lt;- 1 return(output_idx) } idx_entire_length lt;- 1:length(x) if (any(x == special_val)) { # route (b) idx_to_remove lt;- which(x == special_val) output_idx lt;- idx_entire_length[-idx_to_remove] return(output_idx) } # else output_idx lt;- idx_entire_length # route (c) return(output_idx) } get_indexes(my_vec_1, 4) #gt; [1] 1 2 3 4 5 get_indexes(my_vec_2, 4) #gt; [1] 1 get_indexes(my_vec_3, 4) #gt; [1] 1 2 3 5 get_indexes(my_vec_4, 4) #gt; [1] 1 2 3
Я предполагаю, что должен быть какой repeat
-то блок или while
цикл, но я не могу понять, как его правильно (и эффективно) реализовать.
Ответ №1:
Вы можете попробовать
foo lt;- function(x, y){ tmp lt;- which(x != y) if(dplyr::n_distinct(x[x!=y])lt;=1){ tmp lt;- 1 } return(tmp) }
Вместо n_distinct()
этого вы можете использовать length(unique())
Результат:
lapply(list(my_vec_1, my_vec_2, my_vec_3, my_vec_4), foo, 4) [[1]] [1] 1 2 3 4 5 [[2]] [1] 1 [[3]] [1] 1 2 3 5 [[4]] [1] 1
Ответ №2:
Вы можете повторить условие для прохождения (а) внутри условия (б), например:
f lt;- function(x, treatment){ if(var(x) == 0) 1 else { if(treatment %in% x) { x[-which(x == treatment)] |gt; ((.) if(var(.) == 0) 1 else (1:length(x))[-which(x == treatment)])() } else { 1:length(x) } } } lapply(list(v1, v2, v3, v4), f, 4) [[1]] [1] 1 2 3 4 5 [[2]] [1] 1 [[3]] [1] 1 2 3 5 [[4]] [1] 1