如何用列表条件程序化过滤data.table?求类似pandas query的方法
Great question! Ditching the error-prone eval(parse()) approach for a cleaner, programmatic way to filter data.table makes total sense—let's look at a few approaches that mimic the flexibility of pandas' query() with keyword-style arguments.
1. Direct List Matching (Simplest for Equality Checks)
data.table has native support for filtering with named lists, which is perfect for your use case where you're checking equality against column values. This avoids string parsing entirely:
library(data.table) setDT(dat4) # Your condition list ab <- list(Clinic = TRUE, Hospital = FALSE) # Filter directly using the list + `on` argument ad <- dat4[ab, on = names(ab)]
How this works: The on parameter tells data.table which columns to match against the list's keys. It automatically translates the list into the equivalent of Clinic == TRUE & Hospital == FALSE under the hood.
2. Dynamic Expression Building (For More Complex Conditions)
If you need to handle more than just equality checks (e.g., >, <, %in%), you can build a filter expression programmatically using rlang tools—no string parsing required:
library(data.table) library(rlang) library(purrr) setDT(dat4) ab <- list(Clinic = TRUE, Hospital = FALSE) # Build a list of conditions (e.g., Clinic == TRUE, Hospital == FALSE) condition_list <- imap(ab, ~ sym(.y) == .x) # Unpack the conditions into a single expression joined by `&` filter_expr <- expr(!!!condition_list) # Apply the filter ad <- dat4[eval(filter_expr)]
This approach is safer and more maintainable than eval(parse()) because it works directly with R's expression objects instead of raw strings. You can easily modify it for other operators—just swap == with > or %in% as needed.
3. Custom Wrapper Function (Mimic pandas' query() Syntax)
If you want a function that feels exactly like pandas' query() (accepting keyword arguments directly), wrap the logic above into a reusable function:
library(data.table) library(rlang) library(purrr) dt_query <- function(dt, ...) { # Capture keyword arguments as a list filter_args <- list(...) # Build and evaluate the filter expression filter_expr <- expr(!!!imap(filter_args, ~ sym(.y) == .x)) dt[eval(filter_expr)] } # Use it just like pandas' query()! ad <- dt_query(dat4, Clinic = TRUE, Hospital = FALSE)
Why This Is Better Than Your Original Approach
Your original eval(parse()) method works, but it has downsides:
- Risky: If column names contain special characters or user input is untrusted, it can lead to unexpected behavior or code injection.
- Hard to debug: String-based conditions are harder to inspect and modify than expression objects.
- Less idiomatic: The methods above align with
data.table's native design, making your code more readable for otherdata.tableusers.
内容的提问来源于stack exchange,提问作者JeanVuda

