Условно добавить именованные элементы в список - PullRequest
1 голос
/ 23 мая 2019

У меня есть функция для выполнения действий с переменным списком фреймов данных в зависимости от выбора пользователя.Функция в основном выполняет общие действия, но есть несколько действий, которые зависят от данных.

Мой код работает нормально, если выбраны все кадры данных, но я не могу заставить его работать, если не все кадры данных выбраны.

Ниже приведен минимальный воспроизводимый пример:

# User switches.
df1Switch <- TRUE
df2Switch <- TRUE
df3Switch <- TRUE

# DF creation.
set.seed(1)
df <- data.frame(X=sample(1:10), Y=sample(11:20))
if (df1Switch) df1 <- df
if (df2Switch) df2 <- df
if (df3Switch) df3 <- df

# Function to do something.
fn_something <- function(file_list, file_names) {
  df <- file_list
  # Do lots of generic things.
  df$Z <- df$X + df$Y
  # Do a few specific things.
  if (file_names == "Name1") df$X <- df$X + 1 
  else if (file_names == "Name2") df$X <- df$Z - 1
  else if (file_names == "Name3") df$Y <- df$X + df$Y 
  return(df)
}

# Call function to do something.
file_list <- list(Name1=df1, Name2=df2, Name3=df3)
file_names <- names(file_list)
all_df <- do.call(rbind,mapply(fn_something, file_list, file_names, 
SIMPLIFY=FALSE))

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

Вывод выглядит примерно так (фактические числа не важны):

           X     Y    Z
Name1.1    4    13   16
Name1.2    5    12   16 
Name1.3    6    16   21 
   :       :     :    :
Name2.1   15    13   16
   :       :     :    : 

проблема возникает, если пользователь выбирает не создавать некоторые кадры данных, например:

# User switches.
df1Switch <- TRUE
df2Switch <- FALSE
df3Switch <- TRUE

Неудивительно, что в этом случае ошибка объекта не найдена:

> # Call function to do something.
> file_list <- list(Name1=df1, Name2=df2, Name3=df3)
Error: object 'df2' not found

Что я хотел быdo - условно указать содержимое file_list в соответствии с этим псевдокодом:

file_list <- list(if (df1Switch) {Name1=df1}, if (df2Switch) {Name2=df2}, if (df3Switch) {Name3=df3})

Я встречал list.foldLeft Условно объединить элементы списка , но я не знаюесли это подходит.

1 Ответ

1 голос
/ 23 мая 2019

(я еще раз хеширую свой комментарий:)

В общем, я бы рекомендовал вам рассмотреть возможность использования списка списка данных вместо отдельных кадров.Мое обоснование для этого:

  • при условии, что каждый кадр структурирован (почти) одинаково;и
  • при условии, что то, что вы делаете с одним кадром, вы делаете (или, по крайней мере, можете) со всеми кадрами;тогда
  • проще list_of_frames <- lapply(list_of_frames, some_func), чем сделать что-то вроде:

    for (nm in c("df1", "df2", "df3")) {
      d <- get(nm)
      d <- some_func(d)
      assign(nm, d)
    }
    

    особенно при работе с неглобальными средами (т. е. делать это внутри функции).

Чтобы было ясно, "проще" субъективно: хотя он и выигрывает код-гольф, мне гораздо легче читать и понимать, что "я бегу some_func для каждого элемента list_of_frames и сохранения результата ".(Вы даже можете сохранить его в новом списке кадров, тем самым оставив исходные кадры нетронутыми.)

Вы также можете сделать что-то условно, как в

needs_work <- sapply(list_of_frames, some_checker_func) # returns logical
# or
needs_work <- c("df1", "df2") # names of elements of list_of_frames
list_of_frames[needs_work] <- lapply(list_of_frames[needs_work], some_func)

Сказав, что ... прямой ответ на ваш один вкладыш:

c(if (df1Switch) list(Name1=df1), if (df2Switch) list(Name2=df2), if (df3Switch) list(Name3=df3))

Это основывается на том факте, что неустановленный else приводит к NULL и сжатию NULL (отбрасывание)характеристика c().Вы можете увидеть это в действии с:

c(if (T) list(a=1), if (T) list(b=2), if (T) list(d=4))
# $a
# [1] 1
# $b
# [1] 2
# $d
# [1] 4

c(if (T) list(a=1), if (FALSE) list(b=2), if (T) list(d=4))
# $a
# [1] 1
# $d
# [1] 4
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...