Split up `...` arguments and distribute to multiple functions
Separate Lists If you really want to pass different sets of parameters to different functions then it's probably cleaner to specify separate lists:
foo <- function(x, y, sum = list(), grep = list()) {
list(sum = do.call("sum", c(x, sum)), grep = do.call("grep", c("abc", y, grep)))
}
# test
X <- c(1:5, NA, 6:10)
Y <- "xyzabcxyz"
foo(X, Y, sum = list(na.rm = TRUE), grep = list(value = TRUE))
## $sum
## [1] 55
##
## $grep
## [1] "xyzabcxyz"
Hybrid list / ... An alternative is that we could use ... for one of these and then specify the other as a list, particularly in the case that one of them is frequently used and the other is infrequently used. The frequently used one would be passed via ... and the infrequently used via a list. e.g.
foo <- function(x, y, sum = list(), ...) {
list(sum = do.call("sum", c(x, sum)), grep = grep("abc", y, ...))
}
foo(X, Y, sum = list(na.rm = TRUE), value = TRUE)
Here are a couple of examples of the hybrid approach from R itself:
i) The mapply
function takes that approach using both ...
and a MoreArgs
list:
> args(mapply)
function (FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE)
NULL
ii) nls
also takes this approach using both ...
and the control
list:
> args(nls)
function (formula, data = parent.frame(), start, control = nls.control(),
algorithm = c("default", "plinear", "port"), trace = FALSE,
subset, weights, na.action, model = FALSE, lower = -Inf,
upper = Inf, ...)
NULL
Passing along ellipsis arguments to two different functions?
You can pass a list to one of the subfunctions, ie
mainF <- function(f1, f2, ..., args.f2 = list()) {
do.call(f2, c(X=f1(...), args.f2))
}
mainF(function(x) x, function(X, y) X*y, x=5, args.f2 = list(y=3))
(untested, but you got the gist)
R: how to make passing of arguments using ... to multiple functions well-defined?
You can't have multiple versions of ...
in the one environment. What you can do, however, is give each of your called sub-functions a ...
argument of their own. This means they will ignore any parameters passed down that don't match their own formal arguments.
f1 = function(x, n = 1, ...) x + n
g1 = function(x, m = 1, ...) x + m
> h(1:4, n = 2)
$f
[1] 3 4 5 6
$g
[1] 2 3 4 5
Edit to answer added question: you can make a new version of median
, which will override the predefined function when you call it in your own code. (Due to how R namespaces work, other predefined functions will still use the existing version.)
median <- function(x, na.rm=FALSE, ...)
base::median(x, na.rm) # function median exported from base package
How to split list and pass them as separate parameter?
>>> argList = ["egg1", "egg2"]
>>> egg2(*argList)
egg1
egg2
You can use *args (arguments) and **kwargs (for keyword arguments) when calling a function.
Have a look at this blog on how to use it properly.
Apply family of functions for functions with multiple arguments
(Strictly answering the question, not pointing you to a better approach for you particular use here....)
mapply
is the function from the *apply
family of functions for applying a function while looping through multiple arguments.
So what you want to do here is turn each of your matrices into a list of vectors that hold its rows or columns (you did not specify). There are many ways to do that, I like to use the following function:
split.array.along <- function(X, MARGIN) {
require(abind)
lapply(seq_len(dim(X)[MARGIN]), asub, x = X, dims = MARGIN)
}
Then all you have to do is run:
mapply(foo, split.array.along(a, 1),
split.array.along(b, 1))
Like sapply
, mapply
tries to put your output into an array if possible. If instead you prefer the output to be a list, add SIMPLIFY = FALSE
to the mapply
call, or equivalently, use the Map function:
Map(foo, split.array.along(a, 1),
split.array.along(b, 1))
How do I split a string and use it as function arguments in Go?
You can pass any []T
as a parameter of type ...T
using foo...
where foo is of type []T
: spec
exec.Command is of type:
func Command(name string, arg ...string) *Cmd
In this case you will have to pass 1st argument (name) directly and you can expand the rest with ...:
args := strings.Fields(mystr) //or any similar split function
exec.Command(args[0], args[1:]...)
Function having sub functions and their arguments as arguments
Note, the functions should be functions, not strings, for this implementation to work
If you want to return the function called with a set of kwargs
, you're pretty close. I would use a positional argument for func
, then you can pass kwargs
into func
, which is a bit more explicit:
def myfunc(func, **kwargs):
return func(**kwargs)
Then, you could wrap each pair of func, **kwargs
as tuples, and do a for loop:
# This would be called like
somelist = [(np.random.normal, { 'loc' : 0 , 'scale' : 1 , 'size' : 7 }),
(np.random.uniform , { 'low' : 0 , 'high' : 1 , 'size' : 7 })]
results = []
# append results to a list
for func, kwargs in somelist:
results.append(myfunc(func, **kwargs))
By doing it this way, you don't have to worry about what you name any of your variables, and it's a bit more readable. You know that the loop will be dealing with pairs of items, in this case func, kwarg
pairs, and your function can handle those explicitly
Handling the string calls
So there are a few ways to accomplish this task that are a bit more tricky, but overall shouldn't be horrible. You'll need to modify myfunc
to handle the function name:
# func is now a string, unlike above
def myfunc(func, **kwargs):
# function will look like module.class.function
# so split on '.' to get each component. The first will
# be the parent module in global scope, and everything else
# is collected into a list
mod, *f = func.split('.') # f is a list of sub-modules like ['random', 'uniform']
# func for now will just be the module np
func = globals().get(mod)
for cls in f:
# get each subsequent level down, which will overwrite func to
# first be np.random, then np.random.uniform
func = getattr(func, cls)
return func(**kwargs)
The reason I'm using globals().get(mod)
is a) I'm assuming you might not always be using the same module, and b) calling a renamed import from sys.modules
will yield a KeyError
, which isn't what you want:
import sys
import numpy as np
sys.modules['np'] # KeyError
sys.modules['numpy']
# <module 'numpy.random' from '/Users/mm92400/anaconda3/envs/new36/lib/python3.6/site-packages/numpy/random/__init__.py'>
# globals avoids the naming conflict
globals()['np']
# <module 'numpy.random' from '/Users/mm92400/anaconda3/envs/new36/lib/python3.6/site-packages/numpy/random/__init__.py'>
Then getattr(obj, attr)
will return each subsequent module:
import numpy as np
getattr(np, 'random')
# <module 'numpy.random' from '/Users/mm92400/anaconda3/envs/new36/lib/python3.6/site-packages/numpy/random/__init__.py'>
# the dotted access won't work directly
getattr(np, 'random.uniform')
# AttributeError
So, in total:
import numpy as np
func, kwargs = ('np.random.normal', { 'loc' : 0 , 'scale' : 1 , 'size' : 7 })
myfunc(func, **kwargs)
array([ 0.83276777, 2.4836389 , -1.07492873, -1.20056678, -0.36409906,
-0.76543554, 0.90191746])
And you can just extend that to the code in the first section
Related Topics
Replace Negative Values by Zero
Add Multiple Columns to R Data.Table in One Function Call
How to Install an R Package from the Source Tarball on Windows
How to Deal with "'Somefunction' Is Not an Exported Object from 'Namespace:Somepackage'" Error
Ggplot2 Heatmap with Colors for Ranged Values
Why Is Apply() Method Slower Than a for Loop in R
Get Last Row of Each Group in R
In R Markdown in Rstudio, How to Prevent the Source Code from Running Off a PDF Page
How to Replace Nas When Joining Two Data Frames with Dplyr
Installation of Rodbc/Roracle Packages on Os X Mavericks
When Should I Use the := Operator in Data.Table
Count Number of Zeros Per Row, and Remove Rows with More Than N Zeros
Pasting Elements of Two Vectors Alphabetically
How to Draw Stacked Bars in Ggplot2 That Show Percentages Based on Group