Operators

Many functions in R can be written as operators. An operator is a function that takes one or two arguments and can be written without parentheses.

One familiar set of operators is binary operators for arithmetic. R supports arithmetic operations:

> # addition
> 1 + 19
[1] 20

> # multiplication
> 5 * 4
[1] 20

R also includes notation for other mathematical operations, including moduli, exponents, and integer division:

> # modulus
> 41 %% 21
[1] 20?

> # exponents
> 20 ^ 1
[1] 20

> # integer division
> 21 %/% 2
[1] 10

You can define your own binary operators. User-defined binary operators consist of a string of characters between two % characters. To do this, create a function of two variables and assign it to an appropriate symbol. For example, let’s define an operator %myop% that doubles each operand and then adds them together:

> `%myop%` <- function(a, b) {2*a + 2*b}
> 1 %myop% 1
[1] 4
> 1 %myop% 2
[1] 6

Some language constructs are also binary operators. For example, assignment, indexing, and function calls are binary operators:[19]

> # assignment is a binary operator
> # the left side is a symbol, the right is a value
> x <- c(1, 2, 3, 4, 5)

> # indexing is a binary operator too
> # the left side is a symbol, the right is an index
> x[3]
[1] 3

> # a function call is also a binary operator
> # the left side is a symbol pointing to the function argument
> # the right side are the arguments
> max(1, 2)
[1] 2

There are also unary operators that take only one variable. Here are two familiar examples:

> # negation is a unary operator
> -7
[1] -7

> # ? (for help) is also a unary operator
> ?`?`

You may remember from high school math that you always evaluate mathematical expressions in a certain order. For example, when you evaluate the expression 1 + 2 • 5, you first multiply 2 and 5 and then add 1. The same thing is true in computer languages like R. When you enter an expression in R, the R interpreter will always evaluate some expressions first.

In order to resolve ambiguity, operators in R are always interpreted in the same order. Here is a summary of the precedence rules:

Table 6-1 shows a complete list of operators in R and their precedence.

For a current list of built-in operators and their precedence, see the help file for syntax.

Most assignments that we’ve seen so far simply assign an object to a symbol. For example:

> x <- 1
> y <- list(shoes="loafers", hat="Yankees cap", shirt="white")
> z <- function(a, b, c) {a ^ b / c}
> v <- c(1, 2, 3, 4, 5, 6, 7, 8)

There is an alternative type of assignment statement in R that acts differently: assignments with a function on the left-hand side of the assignment operator. These statements replace an object with a new object that has slightly different properties. Here are a few examples:

> dim(v) <- c(2, 4)

> v[2, 2] <- 10

> formals(z) <- alist(a=1, b=2, c=3)

There is a little bit of magic going on behind the scenes. An assignment statement of the form:

fun(sym) <- val

is really syntactic sugar for a function of the form:

`fun<-`(sym,val)

Each of these functions replaces the object associated with sym in the current environment. By convention, fun refers to a property of the object represented by sym. If you write a method with the name method_name<-, then R will allow you to place method_name on the left-hand side of an assignment statement.



[19] Don’t be confused by the closing bracket in an indexing operation or the closing parenthesis in a function call; although this syntax uses two symbols, both operations are still technically binary operators. For example, a function call has the form f(arguments), where f is a function and arguments are the arguments for the function.