Split Up '...' Arguments and Distribute to Multiple Functions

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



Leave a reply



Submit