Is it possible to create a unary operator in R? I know it's possible to create binary operator like this:
setGeneric("%power%", function(x, y) x ^ y)
2 %power% 4
But is it possible to create a unary operator like -. I tried something like:
setGeneric("%-%", function(x) -x)
%-% 3
But it doesn't work
The R parser doesn't support custom unary operators.
A copy of the list of supported operators from the R language definition:
- Minus, can be unary or binary
+ Plus, can be unary or binary
! Unary not
~ Tilde, used for model formulae, can be either unary or binary
? Help
: Sequence, binary (in model formulae: interaction)
* Multiplication, binary
/ Division, binary
^ Exponentiation, binary
%x% Special binary operators, x can be replaced by any valid name
%% Modulus, binary
%/% Integer divide, binary
%*% Matrix product, binary
%o% Outer product, binary
%x% Kronecker product, binary
%in% Matching operator, binary (in model formulae: nesting)
< Less than, binary
> Greater than, binary
== Equal to, binary
>= Greater than or equal to, binary
<= Less than or equal to, binary
& And, binary, vectorized
&& And, binary, not vectorized
| Or, binary, vectorized
|| Or, binary, not vectorized
<- Left assignment, binary
-> Right assignment, binary
$ List subset, binary
(The parser supports also the binary operator := which is not documented here, because it is not used by base R.)
Note that the only custom operators ("%x% Special binary operators, x can be replaced by any valid name") are binary.
So, your only option is overloading an existing unary operator respectively writing a method for it.
Although I am not familiar with setGeneric, I can answer the question
Is it possible to create a unary operator in R?
Yes, sort of, but not really. You can fake it:
# LET'S USE A BINARY OPERATOR TO DEFINE A UNARY OPERATOR:
# THE SYMBOL /*/<- IS SUPPOSED TO LOOK LIKE PERCENT-WILDCARD-PERCENT--ASSIGNMENT-ARROW
`%/*/<-%` <- function ( name , FUN , safe = TRUE ) {
`%//%` <- paste0
NAME <- "%" %//% name %//% "%"
PARENT <- parent.frame ()
if ( safe && exists ( NAME , PARENT ) )
stop ( NAME %//% " exists." )
assign (
x = NAME ,
value = function ( x , ignored ) FUN ( x ) ,
envir = PARENT ) }
.. <- NULL # THIS IS WHAT I MEAN BY FAKING IT...
"-" %/*/<-% `-` # ... `%-%` IS ACTUALLY A BINARY OPERATOR....
1 %-%.. # ... IN THIS CALL, `..` IS THE SECOND ARGUMENT.
# [1] -1
1 %-%.. %-%..
# [1] 1
"t" %/*/<-% `t`
m <- matrix(1:4, 2)
m
# [,1] [,2]
# [1,] 1 3
# [2,] 2 4
m %t%..
# [,1] [,2]
# [1,] 1 2
# [2,] 3 4
"-" %/*/<-% `-`
# Error in "-" %/*/<-% `-` : %-% exists.
i <- floor ( runif ( 9 , min = 1 , max = 10 ) )
i
# [1] 2 3 2 1 7 3 9 5 9
unique(i)
# [1] 2 3 1 7 9 5
"u" %/*/<-% function ( x ) sort ( unique ( x ) )
i %u%..
# [1] 1 2 3 5 7 9
Related
I want to find the function in R which does the same as the function size in Matlab.
In Matlab, if A = [ 1 2 3 4 5], then size(A) = 1 5.
If A =[ 1 2 3;4 5 6], then size(A) = 3 3.
In R, I found that the function dim gives the size of a matrix, but it doesn't apply to vectors.
Please help me solve this problem.
Thanks a lot.
Try dim(A) it's equal to Matlab size(A) function
As you noted dim doesn't work on vectors. You can use this function which will take any number of vectors matrices, data.frames or lists and find their dimension or length:
DIM <- function( ... ){
args <- list(...)
lapply( args , function(x) { if( is.null( dim(x) ) )
return( length(x) )
dim(x) } )
}
# length 10 vector
a <- 1:10
# 3x3 matrix
b <- matrix(1:9,3,3)
# length 2 list
c <- list( 1:2 , 1:100 )
# 1 row, 2 column data.frame
d <- data.frame( a =1 , b = 2 )
DIM(a,b,c,d)
#[[1]]
#[1] 10
#[[2]]
#[1] 3 3
#[[3]]
#[1] 2
#[[4]]
#[1] 1 2
Vectors are dimensionless in R, they have length.
If one wants to consider a vector as a dimensioned object (and later work on that vector), s/he must use t() (transpose) (that in essence makes it 1-dimensional array).
dim(1:10) # NULL
length(1:10) # 10
dim(t(1:10)) # 1x10
Belated answer, but note that NROW and NCOL give the dimensions of both vectors and matrices/data.frames. So, for example:
> a<-c(1,2,3,4)
> NROW(a);NCOL(a)
[1] 4
[1] 1
If you don't know if the class of variable A is 'matrix' or not, then try:
if (class(A) == "matrix" | class(A) == "data.frame") {
size <- dim(A)
} else {
size <- length(A)
}
size
This should work for your case.
You can use the following command:
c(NROW(w), NCOL(w))
Is there an elegant way to simplify this call?
a <- list(1, 2, 3)
b <- list(4, 5)
conditional = TRUE
if (conditional) {
x <- a
} else {
x <- b
}
x
# [1, 2, 3]
I've tried x <- ifelse(TRUE, a, b), but it assumes the conditional is a vector which must be iterated, so in this case it returns a single value (in this case, 1).
dplyr's if_else, on the other hand, demands that the lists be of equal length. And even if they were, it also iterates through the conditional and would also output a single value 1.
So, is there some clean way of solving this or is the simple if{}else{} the way to go?
Here's a simple one-liner using switch.
x <- switch(TRUE + 1, b, a)
x
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
x <- switch(FALSE + 1, b, a)
x
[[1]]
[1] 4
[[2]]
[1] 5
This uses the switch behavior with integer EXPR as described in documentation -
switch works in two distinct ways depending whether the first argument
evaluates to a character string or a number.
If the value of EXPR is not a character string it is coerced to
integer. Note that this also happens for factors, with a warning, as
typically the character level is meant. If the integer is between 1
and nargs()-1 then the corresponding element of ... is evaluated and
the result returned: thus if the first argument is 3 then the fourth
argument is evaluated and returned.
I have to create a function as: ans(x) which returns the value 2*abs(x), if x is
negative, and the value x otherwise. What command could i use?
Thanks
ans <- function(x){
ifelse(x < 0, 2*abs(x), x)
}
will do.
> ans(2)
[1] 2
> ans(-2)
[1] 4
Explanation:
We can use the built-in base R function ifelse(). The logic is pretty simple:
ifelse(condition, output if condition is TRUE, output if condition is FALSE)
Therefore, ifelse(x < 0, 2*abs(x), x) will do the following:
evaluate whether value x is negative (<0)
if TRUE, return 2*abs(x)
if FALSE, return x
The advantage of ifelse() over traditional if() is the vectorization. if() can only handle a single value, ifelse() will evaluate any vector given as input.
Comparison:
ans_if <- function(x){
if(x < 0){2*abs(x)}else{x}
}
This is the same function, using a traditional if() structure. Giving a single value as input will result in the same output for both functions:
> ans(-2)
[1] 4
> ans_if(-2)
[1] 4
But if you want to input multiple values, let's say
test <- c(-1, -2, 3, -4)
the ifelse() variant will evaluate every element of the vector and generate the correct output as a vector of the same length:
> ans(test)
[1] 2 4 3 8
whereas the if() variant will throw a warning
> ans_if(test)
[1] 2 4 6 8
Warning message:
In if (x < 0) { :
the condition has length > 1 and only the first element will be used
and return the wrong output, as only the first value was used for evaluation (-1) and the operation over the whole vector was based on this evaluation.
I'm attempting to define an infix function %~% that takes a character on the left and an expression on the right and returns a concatenated formula object. So what I want "y" %~% x + z to return y ~ x + z.
However, my function (below) fails to use the + as a symbolic formula operator, and instead defaults to an arithmetic operator. Clearly, the ~ infix function acheives this, but it's a primitive function, so I (think I) can't go swipe the code, and I don't know how to incorporate it into the function definition to acheive my desired results.
`%~%` <- function(x, y) {
y <- deparse(substitute(y))
formula(paste(x, "~", y)
}
A solution is to use the ~ operator when calling the function:
"y" %~%~ x + z
but I'm wondering if there is a way to prevent the evaluation of + as an arithmetic operator in the function definition so that I can simply use %~%.
The order or operator precedence is fixed in R, and a little experimentation (or checking of the ?Syntax help page) shows that the special operators bind tighter than the + and - operators:
`%~%` = function(left,right){
cat("left: ",as.character(substitute(left)), " right: ", as.character(substitute(right)),'\n')
return(100)
}
which yields:
> 2 %~% 1 + 3
left: 2 right: 1
[1] 103
> 2 %~% (1 + 3)
left: 2 right: ( 1 + 3
[1] 100
or maybe a bit more clearly:
zz <- function(x){
x <- substitute(x)
cat(sprintf("%s [%s] %s\n",
as.character(deparse(x[[2]])),
as.character(deparse(x[[1]])),
as.character(deparse(x[[3]]))))}
which yields:
> zz(1 + 2)
1 [+] 2
> zz(1 + 2:3)
1 [+] 2:3
> zz(1 + 2%foo%3)
1 [+] 2 %foo% 3
> zz(2%foo%3+1)
2 %foo% 3 [+] 1
Note also that formula's capture the environment in which they are created, so creating a formula in a helper function may have some unexpected and difficult to debug consequences if you don't take care to bind the correct environment to your formula object.
I'm using brute force right now..
x <- 1.03
Value <- c((1/x)^20,(1/x)^19,(1/x)^18,(1/x)^17,(1/x)^16,(1/x)^15,(1/x)^14,(1/x)^13,(1/x)^12,(1/x)^11,(1/x)^10,(1/x)^9,(1/x)^8,(1/x)^7,(1/x)^6,(1/x)^5,(1/x)^4,(1/x)^3,(1/x)^2,(1/x),1,x,x^2,x^3,x^4,x^5,x^6,x^7,x^8,x^9,x^10,x^11,x^12,x^13,x^14,x^15,x^16,x^17,x^18,x^19,x^20)
Value
but I would like to use an increment loop just like the for loop in java
for(integer I = 1; I<=20; I++)
^ is a vectorized function in R. That means you can simply use x^(-20:20).
Edit because this gets so many upvotes:
More precisely, both the base parameter and the exponent parameter are vectorized.
You can do this:
x <- 1:3
x^2
#[1] 1 4 9
and this:
2^x
#[1] 2 4 8
and even this:
x^x
#[1] 1 4 27
In the first two examples the length-one parameter gets recycled to match the length of the longer parameter. Thats why the following results in a warning:
y <- 1:2
x^y
#[1] 1 4 3
#Warning message:
# In x^y : longer object length is not a multiple of shorter object length
If you try something like that, you probably want what outer can give you:
outer(x, y, "^")
# [,1] [,2]
#[1,] 1 1
#[2,] 2 4
#[3,] 3 9
Roland already addressed the fact that you can do this vectorized, so I will focus on the loop part in cases where you are doing something more that is not vectorized.
A Java (and C, C++, etc.) style loop like you show is really just a while loop. Something that you would like to do as:
for(I=1, I<=20, I++) { ... }
is really just a different way to write:
I=1 # or better I <- 1
while( I <= 20 ) {
...
I <- I + 1
}
So you already have the tools to do that type of loop. However if you want to assign the results into a vector, matrix, array, list, etc. and each iteration is independent (does not rely on the previous computation) then it is usually easier, clearer, and overall better to use the lapply or sapply functions.