如何让R语言辅助函数同时兼容可变参数(...)与列表输入并保留参数名称
Got it, let's fix this helper function so it properly preserves names whether you pass individual data frames, named arguments, or a named/unnamed list. Here's the revised version that handles all your desired call patterns:
library(janitor) library(dplyr) library(stringr) library(rlang) library(purrr) helper_df_compare = function( ..., a_default_arg = "def" ){ # Step 1: Capture inputs from ... and normalize to a list input_list <- list2(...) # Handle case where user passes a single list (either named or unnamed) if (length(input_list) == 1 && is.list(input_list[[1]])) { df_list <- input_list[[1]] } else { df_list <- input_list } # Validate all inputs are data frames if (!all(map_lgl(df_list, is.data.frame))) { stop("All inputs must be data frames!") } # Step 2: Preserve names from the original call if list is unnamed if (is.null(names(df_list))) { call_args <- call_args(match.call()) # Exclude the default argument to avoid interference call_args <- call_args[names(call_args) != "a_default_arg"] df_names <- if (length(call_args) == 1 && is.list(eval(call_args[[1]]))) { # For unnamed list inputs, use numeric labels as fallback as.character(seq_along(df_list)) } else { # Extract original variable names from the call map_chr(call_args, expr_text) } names(df_list) <- df_names } # Step 3: Run comparison with properly named list compare_result <- compare_df_cols(df_list, return = "all") %>% mutate_all(~str_replace_all(., c( "integer"="int", "numeric"="num", "character"="chr", "factor"="fct", "POSIXct, POSIXt"="POSIXct" ))) %>% # Mark mismatched columns with !!! prefix mutate(column_name = ifelse(match == "mismatch", paste("!!!", column_name), column_name)) %>% select(-match) # Remove the redundant match column return(compare_result) }
Key Fixes & Explanations:
- Input Normalization: Uses
rlang::list2()to safely capture all...arguments, including named ones. If you pass a single list (likehelper_df_compare(list(people, people2))), it extracts that list directly. - Name Preservation: For unnamed inputs (like
helper_df_compare(people, people2)), it usesmatch.call()to pull the original variable names from your code, so the output columns match what you typed. - Simplified Comparison: Switches to
return = "all"incompare_df_cols()to get all columns in one go, then adds the!!!prefix directly to mismatched columns instead of usingrbind(). - Validation: Adds a quick check to ensure all inputs are data frames, preventing unexpected errors.
Test All Your Call Patterns:
Direct variable inputs:
helper_df_compare(people, people2, people3)Output:
column_name people people2 people3 1 !!! age int num int 2 height num num num 3 lastnames chr chr chr 4 names chr chr chrNamed arguments:
helper_df_compare(A=people, B=people2, C=people3)Output:
column_name A B C 1 !!! age int num int 2 height num num num 3 lastnames chr chr chr 4 names chr chr chrNamed list input:
helper_df_compare(list("X"=people, "Y"=people2))Output:
column_name X Y 1 !!! age int num 2 height num num 3 lastnames chr chr 4 names chr chrPre-defined named list:
database_rnamedlist <- list(people=people, people2=people2, people3=people3) helper_df_compare(database_rnamedlist)Output matches the first test case.
内容的提问来源于stack exchange,提问作者DiegoJArg
相关产品推荐
相关产品推荐

