назначить функцию в цикле - PullRequest
2 голосов
/ 21 марта 2012

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

assign.instrumentslist = function()
{
  for(instList in lists.instruments)
  {
  assign(
      paste("test", instList, sep="."),
      function() {print(instList)},
      envir = .GlobalEnv
      )
   }
}

lists.instruments = c("CL", "HO", "GC")
assign.instrumentslist()
test.CL()
# return "GC"

thx

Ответы [ 3 ]

4 голосов
/ 21 марта 2012

Наверное, это самый простой способ:

assign.instrumentslist = function() {
  for(instList in lists.instruments) {
    local({
      i <- instList
      assign(
             paste("test", instList, sep="."),
             function() {print(i)},
             pos = .GlobalEnv
             )
    })
  }
}

Ключ заключается в создании локальных объектов (i) в окружении функции. В этом примере среда генерируется как local.

И это действительно очень плохой взлом:

lapply(lists.instruments, 
  function(x) .GlobalEnv[[paste("test1", x, sep=".")]] <- function() print(x))
2 голосов
/ 21 марта 2012

Я могу объяснить поведение, но не уверен, как правильно его решить (окружение причиняет мне боль).

Проблема в том, что ваша анонимная функция подбирает окружение.это среда, в которой он будет искать объекты, включая instList.На первой итерации она получает эту среду <environment: 0x28e19a8>, и это текущая среда для вашей функции, которая оценивается (assign.instrumentslist()):

Browse[2]> environment()
<environment: 0x28e19a8>

На следующей итерации цикла значениеinstList в текущей среде <environment: 0x28e19a8> изменяется на "HO".Теперь и test.CL(), и test.HO() имеют одинаковое окружение, поэтому обращайтесь к одному и тому же instList, который теперь имеет значение "HO".То же самое происходит в последней итерации для test.GC().Следующая отладочная расшифровка показывает это:

debug at #5: assign(paste("test", instList, sep = "."), function() {
    print(instList)
}, envir = .GlobalEnv)
Browse[2]> 
debug at #3: instList
Browse[2]> environment(test.CL)
<environment: 0x28e19a8>
Browse[2]> eval(instList, environment(test.CL))
[1] "CL"
Browse[2]> 
debug at #5: assign(paste("test", instList, sep = "."), function() {
    print(instList)
}, envir = .GlobalEnv)
Browse[2]> 
debug at #3: instList
Browse[2]> environment(test.CL)
<environment: 0x28e19a8>
Browse[2]> eval(instList, environment(test.CL))
[1] "HO"

Когда цикл завершен, среда оценки assign.instrumentslist(), <environment: 0x28e19a8> сохраняется, поскольку она также является средой ваших трех функций.Все они ссылаются на одну и ту же среду и используют значение instList, которое было установлено во время последней итерации вашего цикла.

2 голосов
/ 21 марта 2012

Что не так с использованием аргументов?

AsItShouldBeDone <- 
function(x){
    print(x)
}

> AsItShouldBeDone('CL')
[1] "CL"

Это примерно столько же, сколько печатание: предоставление CL в качестве аргумента вместо дополнительного добавления к имени функции.И вот как вы должны это сделать.

Что не так с вашим решением?:

  • использование assign(): очень неразумно менять свою глобальную среду изнутри функции на любом языке и, безусловно, совершенно против подхода R.Так что не надо.У меня в рабочей области был фрейм данных с именем test.CL.Ну, теперь все прошло ...
  • создание разных функций с разными именами и с одним и тем же кодом.Это почему?Если вы пытаетесь найти ярлык для назначения методов S3 для разных классов, попробуйте следующее.В любом другом случае используйте аргументы, чтобы заставить вашу функцию делать то, что она должна

    test.CL <- test.HO <- test.GC <- function(x) print(x)

  • , ожидая, что значение переменной жестко закодировано в функции изнутрицикл.Нет, это не так.R говорит вам, что это функция:

    > test.CL

    function() {print(instList)}

    <environment: 0x05e32224>

Так что этоделает вполне очевидно: он печатает instList из среды, заданной в среде.Какая среда создана вашей первой функцией.Который содержит значение instList после цикла.Что является последним значением.

Этот механизм взломан методом Кошке.Оно работает.Не потому, что это работает, вы должны использовать это, наоборот;Подобные хакерские среды могут иметь очень забавные побочные эффекты и ни в коем случае не являются стабильным кодом.Плюс, как уже было сказано ранее:

ИСПОЛЬЗУЙТЕ АРГУМЕНТЫ ДЛЯ ХРИСТА!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...