有条件地将命名元素添加到列表中

时间:2019-05-22 21:04:32

标签: r list if-statement

我具有根据用户选择对可变数据帧列表执行操作的功能。该函数主要执行通用操作,但有一些特定于数据帧的操作。

如果选择了所有数据框,我的代码运行正常,但是如果未选择所有数据框,我无法使其正常工作。

以下内容提供了一个最小的可重现示例:

# 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

我想做的是根据此伪代码的行有条件地指定file_list的内容:

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

我遇到了list.foldLeft Conditionally merge list elements,但我不知道这是否合适。

1 个答案:

答案 0 :(得分:1)

(我将重新发表我的评论:)

通常,我鼓励您考虑使用数据帧列表而不是单个帧。我的理由:

  • 假设每个框架(几乎)具有相同的结构;和
  • 假设您要对一帧进行操作(或至少可以)对所有帧进行操作;然后
  • 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)
    }
    

    尤其是在处理非全局环境时(即在函数中执行此操作)。

需要明确的是,“轻松”是主观的:尽管它确实赢得了代码高尔夫,但我发现阅读和理解”我正在{{1的每个元素上运行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)) 导致elseNULL的{​​{1}}压缩(丢弃)特性这一事实。您可以通过以下方式查看它的运行情况:

NULL