Home > database >  change parameters of a function inside that function
change parameters of a function inside that function

Time:03-29

I am trying to change all NA passed to the function to NULL. What I want is not to treat each arg separatedly, by name, but to capture all of them, filter those which are NAand change them to NULL.

foo <- function(a, b = NA, c = NA) {
    print(a)
    print(b)
    print(c)

    # do something to capture all args and change NAs to NULL

    print(a)
    print(b)
    print(c)
}

# expected output
> foo(a = 1)
[1] 1
[1] NA
[1] NA
[1] 1
[1] NULL
[1] NULL

edit: included an argument without a default value

CodePudding user response:

To access a function's arguments, use formals.

foo <- function(a = 1, b = NA, c = NA) {
  print(a)
  print(b)
  print(c)
  
  # do something to capture all args and change NAs to NULL
  frm <- formals()
  cat("-----------\n")
  print(frm)
  frm <- lapply(frm, \(x) {
    if(is.na(x)) NULL else x
  })
  cat("-----------\n")
  with(frm, {
    print(a)
    print(b)
    print(c)
  })
}
foo()
#> [1] 1
#> [1] NA
#> [1] NA
#> -----------
#> $a
#> [1] 1
#> 
#> $b
#> [1] NA
#> 
#> $c
#> [1] NA
#> 
#> -----------
#> [1] 1
#> NULL
#> NULL

Created on 2022-03-28 by the reprex package (v2.0.1)


Edit

The comments suggest that the question is also asking for match.call. But its return values must be coerced to list.

check_arrays <- function(a, b, c, d) { 
  print(as.list(match.call()))
}
check_arrays(a = 'teststring', b = 1, c = NA, d = NA)
#> [[1]]
#> check_arrays
#> 
#> $a
#> [1] "teststring"
#> 
#> $b
#> [1] 1
#> 
#> $c
#> [1] NA
#> 
#> $d
#> [1] NA

Created on 2022-03-28 by the reprex package (v2.0.1)

And an example changing all NA arguments to NULL, just like the first function above is the following.

check_arrays <- function(a, b, c, d) {
  print(a)
  print(b)
  print(c)
  print(d)
  
  # do something to capture all args and change NAs to NULL
  # note that the first element of the list is the function 
  # name, remove it
  args_list <- as.list(match.call())[-1]
  cat("-----------\n")
  print(args_list)
  args_list <- lapply(args_list, \(x) {
    if(is.na(x)) NULL else x
  })
  cat("-----------\n")
  with(args_list, {
    print(a)
    print(b)
    print(c)
    print(d)
  })
}
check_arrays(a = 'teststring', b = 1, c = NA, d = NA)
#> [1] "teststring"
#> [1] 1
#> [1] NA
#> [1] NA
#> -----------
#> $a
#> [1] "teststring"
#> 
#> $b
#> [1] 1
#> 
#> $c
#> [1] NA
#> 
#> $d
#> [1] NA
#> 
#> -----------
#> [1] "teststring"
#> [1] 1
#> NULL
#> NULL

Created on 2022-03-28 by the reprex package (v2.0.1)

CodePudding user response:

Quick disclaimer: the solutions offered here will work if your arguments are scalars. If they are vectors or other objects, the outcome may be quite a bit different.

You can use a ls and assign within a loop and avoid having to refer to the arguments from a list after the conversion.

foo <- function(a = 1, b = NA, c = NA) {
  print(a)
  print(b)
  print(c)
  
  arg_names <- ls()
  
  for (arg in arg_names){
    tmp <- if (is.na(get(arg))) NULL else get(arg)
    assign(arg, tmp)
  }
  
  print(a)
  print(b)
  print(c)
}

foo()

Alternatively, if you'd rather work with lists, you can use mget and list2env

foo <- function(a = 1, b = NA, c = NA) {
  print(a)
  print(b)
  print(c)
  
  arg_names <- ls()
  arg <- mget(arg_names)
  arg <- lapply(arg, 
                function(a) if (is.na(a)) NULL else a)

  list2env(arg, envir = environment())

  print(a)
  print(b)
  print(c)
}

foo()
  •  Tags:  
  • r
  • Related