R语言函数可选参数:两种写法差异及代码优化咨询
Hey there! Let's break down exactly why your second createTibble function is throwing an error, then walk through a few ways to eliminate that duplicate code without sacrificing readability.
The Root of the Error
Your mistake comes from mixing up two very different tools:
if_else()(anddplyr::if_else()) is a vector-wise function. It’s designed to pick values for individual elements based on a logical vector of the same length. For example,if_else(c(TRUE, FALSE), 1, 0)returnsc(1,0).- But you’re trying to use it as a flow control tool (like base R’s
if/else) to choose between two entire data frames. Themissing(wk)check gives a singleTRUE/FALSEvalue, but the branches return fulltbl_dfobjects—this type mismatch is why you get the error:condition must be a logical vector, not a tbl_df/tbl/data.frame.
Fixes to Avoid Duplicate Code
Here are three clean ways to rewrite your function without repeating that long pipeline:
1. Extract Repeated Code to a Middle Variable
This is the most straightforward approach—handle all the shared processing first, then add the optional filter only if wk is provided:
createTibble <- function(i, yr, wk){ # Do all the shared processing once processed_data <- list_sheets[[i]] %>% filter(LASTUSER %in% users) %>% mutate( year = as.numeric(format(DATEMODIFI, "%Y")), month = as.numeric(format(DATEMODIFI, "%m")), week = week(DATEMODIFI), day = as.numeric(format(DATEMODIFI, "%d")) ) %>% select(-DATEMODIFI) %>% filter(year == yr) # Add week filter only if wk is supplied if (!missing(wk)) { processed_data <- processed_data %>% filter(week == wk) } processed_data }
2. Combine Filters in a Single filter() Call
You can also wrap the week condition in a base R if() directly inside the filter() function. If wk is missing, we just return TRUE (which doesn’t filter any rows):
createTibble <- function(i, yr, wk){ list_sheets[[i]] %>% filter(LASTUSER %in% users) %>% mutate( year = as.numeric(format(DATEMODIFI, "%Y")), month = as.numeric(format(DATEMODIFI, "%m")), week = week(DATEMODIFI), day = as.numeric(format(DATEMODIFI, "%d")) ) %>% select(-DATEMODIFI) %>% filter( year == yr, # Only check week if wk is provided if (missing(wk)) TRUE else week == wk ) }
3. Use purrr::when() for Chained Branching
If you’re comfortable with the tidyverse’s purrr package, when() lets you write sequential condition checks right in your pipe:
library(purrr) createTibble <- function(i, yr, wk){ list_sheets[[i]] %>% filter(LASTUSER %in% users) %>% mutate( year = as.numeric(format(DATEMODIFI, "%Y")), month = as.numeric(format(DATEMODIFI, "%m")), week = week(DATEMODIFI), day = as.numeric(format(DATEMODIFI, "%d")) ) %>% select(-DATEMODIFI) %>% filter(year == yr) %>% when( !missing(wk) ~ filter(., week == wk), . ~ . # Return the data as-is if wk is missing ) }
All three of these approaches eliminate duplicate code while keeping your logic clear—no more repeating that entire pipeline twice!
内容的提问来源于stack exchange,提问作者Karl Johnson

