Thanks Ian (and others), Taking the advice of ?"..." (which I should have done at the outset ... duhh!), the following seems to be the simplest solution, adequate for my needs at least:
f <- function(x, ...){ lapply(seq_along(x), \(i)switch(x[i], ..., NA)) } (the usual argument checking etc. should be added, of course.) Comparing this to the ...xx() functions that I previously gave, which are the same as names(list(...)) etc. without the overhead of unnecessary evaluation, gives: g <- function(...){ one <- f(z,...) two <- lapply(charmatch(z, ...names()), \(i)...elt(i)) list(one = one, two = two) } > k <- 5 > z <- c("a","c") > g(b=2, a=1, c = k) $one $one[[1]] [1] 1 $one[[2]] [1] 5 $two $two[[1]] [1] 1 $two[[2]] [1] 5 As always, corrections and comments welcomed. Cheers, Bert On Thu, Jan 9, 2025 at 5:12 AM Ian Farm <ian.f...@maine.edu> wrote: > I might add that there seems to be a subtle difference between using > `...elt()` and `match.call()`, which is that the former causes `a` itself > to be evaluated while the latter doesn't: > ``` > # Some approaches that have been suggested: > > # 1. Using `list()` (Bert Gunter) > f1 <- function(...) list(...)[["a"]] > # 2. Using `...elt()` (Bert Gunter) > f2 <- function(...) ...elt(match("a", ...names())) > # 3. Using argument matching (Hadley Wickham) > f3 <- function(...) (\(a, ...) a)(...) > # 4. Using `match.call()` > f4 <- function(...) eval(match.call()[["a"]], parent.frame()) > > ff <- list(f1 = f1, f2 = f2, f3 = f3, f4 = f4) > > sapply(ff, \(f) { > f(b = 2, a = 1, c = 3) > }) > #> f1 f2 f3 f4 > #> 1 1 1 1 > > # View the (defused) arguments after `a` has been accessed: > > # returns an expression if the argument has not been evaluated, and a > number if it has > check_forced_args <- function(f) { > body(f) <- call("{", body(f), quote(rlang::enexprs(...))) > # pass `f()` some expressions to see which are evaluated > f(a = cos(0), b = sqrt(4)) > } > # make a data frame showing the defused arguments for each function > lapply(ff, check_forced_args) |> do.call(rbind, args = _) |> > as.data.frame() > > #> a b > #> f1 1 2 # all the arguments are forced > #> f2 1 sqrt(4) # only `a` is forced > #> f3 1 sqrt(4) # only `a` is forced > #> f4 cos(0) sqrt(4) # none of the arguments are forced > ``` > > Also, here's a possible way to adapt Hadley Wickham's approach so that it > takes the name of the argument as a string, though it does lose the > elegance: > ``` > pick_arg <- function(nm) { > as.function(c( > setNames(alist(. = , . = ), c(nm, "...")), > as.symbol(nm) > )) > } > > z <- "a" > f5 <- function(...) { > pick_arg(z)(...) > } > f5(b = 2, a = 1, c = 3) > #> [1] 1 > ``` > > Regards, > Ian > ____ > Ian Farm, Laboratory Manager > University of Maine Agroecology Lab > > > On Wed, Jan 8, 2025 at 5:58 PM Bert Gunter <bgunter.4...@gmail.com> wrote: > >> That's very nice, Hadley. Simple and clean. Never would have thought of it >> myself. >> >> As usual, however, in the course of my churnings, I have a further >> complication to add. But first ... >> >> **TO ALL**: Feel free to ignore the following, as I'm just fooling around >> here and don't want to waste your time with my stupid stuff. >> >> Anyway, the complication is motivated by the use of formals() or otherwise >> that *programmatically* generates a character representation of the >> arguments I want to select. So, for example: >> >> > z <- "a" >> ## Then: >> f1 <- function(...){ >> ...elt(match(z, ...names())) ## since z gets evaluated in the call >> } >> ## still works. >> > f1(b =2, a=1, c=3) >> [1] 1 >> >> But I haven't figured out how to modify your suggestion -- at least in a >> simple way -- to do the same. Likely I've missed something, though. >> >> >> Cheers, >> Bert >> >> >> >> >> >> >> On Wed, Jan 8, 2025 at 12:51 PM Hadley Wickham <h.wick...@gmail.com> >> wrote: >> >> > I'd propose an alternative that I think is superior: rely on the >> semantics >> > of ... to do the work for you: >> > >> > f1 <- function(...){ >> > one <- list(...)[['a']] >> > two <- ...elt(match('a', ...names())) >> > c(one, two, three(...)) >> > } >> > >> > three <- function(a, ...) { >> > a >> > } >> > >> > f1(a = 1, b = 2, c = 3) >> > #> [1] 1 1 1 >> > >> > >> > On Sun, Jan 5, 2025 at 12:00 PM Bert Gunter <bgunter.4...@gmail.com> >> > wrote: >> > >> >> Consider: >> >> >> >> f1 <- function(...){ >> >> one <- list(...)[['a']] >> >> two <- ...elt(match('a', ...names())) >> >> c(one, two) >> >> } >> >> ## Here "..." is an argument list with "a" somewhere in it, but in an >> >> unknown position. >> >> >> >> > f1(b=5, a = 2, c=7) >> >> [1] 2 2 >> >> >> >> Which is better for extracting a specific named argument, one<- or >> >> two<- ? Or a third alternative that is better than both? >> >> Comments and critiques welcome. >> >> >> >> Cheers, >> >> Bert >> >> >> >> ______________________________________________ >> >> R-help@r-project.org mailing list -- To UNSUBSCRIBE and more, see >> >> https://stat.ethz.ch/mailman/listinfo/r-help >> >> PLEASE do read the posting guide >> >> https://www.R-project.org/posting-guide.html >> >> and provide commented, minimal, self-contained, reproducible code. >> >> >> > >> > >> > -- >> > http://hadley.nz >> > >> >> [[alternative HTML version deleted]] >> >> ______________________________________________ >> R-help@r-project.org mailing list -- To UNSUBSCRIBE and more, see >> https://stat.ethz.ch/mailman/listinfo/r-help >> PLEASE do read the posting guide >> https://www.R-project.org/posting-guide.html >> and provide commented, minimal, self-contained, reproducible code. >> > [[alternative HTML version deleted]] ______________________________________________ R-help@r-project.org mailing list -- To UNSUBSCRIBE and more, see https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide https://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.