Skip to content

argument rationalization

3 messages · Brian Ripley, robin hankin

#
Hi

I am writing a bunch of functions that take two, three or four
arguments.  These functions operate on vectors of the same length; 
but  I want the function
to behave sensibly if one or more arguments are scalars.  "+" does 
this for two arguments:


"+"(1:10,3)    # interpreted as "+"(1:10,rep(3,10))

But my functions can take more arguments.  Say f() takes three:

f(1:10,1:10,1:10)  # default
f(3,1:10,1:10)     # interpret as f(rep(3,10),1:10,1:10)
f(1:10,3,1:10)     # interpret as f(1:10,rep(3,10),1:10)
f(1:10,3,5)        # interpret as f(1:10,rep(3,10),rep(5,10))

and h() takes four:

h(2,4,5,1:10)    # interpret as h(rep(2,10),rep(4,10),rep(5,10),1:10)
h(2,3,1:10,1)    # interpret as h(rep(2,10),rep(3,10),1:10,rep(1:10)
h(1:20,3,1:20,1) # interpret as h(1:20,rep(3,20),1:20,rep(1,20))

I haven't got any that need five yet, but this may change in the future.
How do I implement this desired behaviour nicely?

(I pass the arguments to .C(), which is why I need this).
#
I think you should implement recycling, ideally at C level.
But you could have

f <- function(x, y, z)
{
    n <- max(length(x), length(y), length(z))
    .C("something", as.double(rep(x, len=n)), as.double(rep(y, len=n)),
       as.double(rep(z, len=n)), as.integer(n), ans)$ans
}
On Mon, 15 Nov 2004, Robin Hankin wrote:

            

  
    
#
> But you could have
  >
  > f <- function(x, y, z)
  > {
  >    n <- max(length(x), length(y), length(z))
  >    .C("something", as.double(rep(x, len=n)), as.double(rep(y, len=n)),
  >       as.double(rep(z, len=n)), as.integer(n), ans)$ans
  > }


yes!  this works exactly as desired.  Thank you.  Another thing
that is incidentally satisfied by this scheme is to preserve
attributes such as dimensions and dimnames.  It seems to me to make
sense to use the attributes of the longest argument, and then set them
after the call


to wit

f <- function(x, y, z)
{
    lens <- c(length(x), length(y), length(z))
    all.attributes <- list(attributes(x),attributes(y),attributes(z))
    n <- max(lens)
    attributes.desired <- all.attributes[[which.max(lens)]]

    .C("something", as.double(rep(x, len=n)), as.double(rep(y, len=n)),
       as.double(rep(z, len=n)), as.integer(n), ans)$ans

    attributes(ans) <- attributes.desired
    return(ans)
}



Is this good practice?

best wishes

rksh