Версии lapply() и mclapply(), которые избегают избыточной обработки

Я ищу версии lapply() и mclapply(), которые обрабатывают только уникальные элементы списка аргументов X. Что-то подобное уже существует?

EDIT: Другими словами, я хочу, чтобы lapply() не беспокоила обработка дубликатов, но я хочу, чтобы length(lapply(X, ...)) равнялось length(X), а не length(unique(X)) (и соответствующие значения совпадали). Кроме того, я предполагаю, что каждый элемент X довольно мал, поэтому получение уникальных значений не должно вызывать особых проблем.

Текущее поведение:

long_computation <- function(task){
  cat(task, "\n")
# Sys.sleep(1000) # 
  return(task)
}
tasks <- rep(LETTERS[1:2], 2)
lapply(tasks, long_computation)

## A
## B
## A
## B
## [[1]]
## [1] "A"
## 
## [[2]]
## [1] "B"
## 
## [[3]]
## [1] "A"
## 
## [[4]]
## [1] "B"

Желаемое поведение:

lapply (задачи, long_computation)

## A
## B
## [[1]]
## [1] "A"
## 
## [[2]]
## [1] "B"
## 
## [[3]]
## [1] "A"
## 
## [[4]]
## [1] "B"

Вы можете найти предполагаемый вариант использования здесь.


person landau    schedule 31.10.2017    source источник
comment
уникальные входные комбинации перед переходом к итерациям применения   -  person hrbrmstr    schedule 31.10.2017
comment
Я бы хотел, но мне нужно, чтобы мне вернули полные расширенные результаты, дубликаты и все такое. Даже если дублирование расположено нерегулярно, например X = c(1, 2, 2, 3, 2, 2, 5, 7, 7, 7)   -  person landau    schedule 31.10.2017
comment
Другими словами, length(lapply(X, ...)) должно равняться length(X).   -  person landau    schedule 31.10.2017


Ответы (2)


Вы можете попробовать что-то вроде этого: я создал объект map, который сохраняет результат после long_computation для каждого уникального «ключа». Как только встречается существующий «ключ», он возвращается из map, иначе вызывает функцию long_computation и сохраняет результат в map для будущего использования. Не уверен, что это идеальный способ, но он работает.

tasks <- rep(letters[1:2], 2)
map=list()

lapply(tasks,function(t){if(t %in% names(.GlobalEnv$map)){
    return(.GlobalEnv$map[[t]])
}else{
    result=toupper(t)
        if(!t %in% names(.GlobalEnv$map)){
            .GlobalEnv$map[[t]]=result
        }
    }
})
person tushaR    schedule 31.10.2017
comment
Это хорошая мысль, но похоже, что в mclapply() могут возникнуть условия гонки, если несколько процессов пытаются получить доступ к .GlobalEnv$map[[t]]. - person landau; 31.10.2017
comment
@landau Но я не использовал здесь mclapply. Кроме того, если вы хотите пойти по параллельному/многоядерному маршруту, переменные могут быть разделены между несколькими ядрами с помощью опции export. Возможно, это невозможно с mclapply, но возможно с foreach. - person tushaR; 31.10.2017

Это действительно работает:

lightly_parallelize_atomic <- function(X, FUN, jobs = 1, ...){
  keys <- unique(X)
  index <- match(X, keys)
  values <- mclapply(X = keys, FUN = FUN, mc.cores = jobs, ...)
  values[index]
}

И в моем случае все в порядке, что X является атомарным.

Но было бы неплохо найти что-то, уже встроенное в пакет или R изначально.

person landau    schedule 31.10.2017