Как написать функцию, которая возвращает индексы входного вектора в соответствии с некоторыми правилами, используя повтор, цикл while или другой метод итерации

#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), мы могли бы столкнуться с ситуацией, в которой все векторные элементы теперь одинаковы. В таком случае мы хотели бы повторить (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