R: += (plus equals) and ++ (plus plus) equivalent from c++/c#/java, etc.?
Asked Answered
T

10

207

Does R have a concept of += (plus equals) or ++ (plus plus) as c++/c#/others do?

Thereunder answered 21/4, 2011 at 2:25 Comment(1)
No, to do x += 1 or x++ - x = x + 1 works.Lollard
A
151

No, it doesn't, see: R Language Definition: Operators

Alburg answered 21/4, 2011 at 2:40 Comment(0)
L
74

Following @GregaKešpret you can make an infix operator:

`%+=%` = function(e1,e2) eval.parent(substitute(e1 <- e1 + e2))
x = 1
x %+=% 2 ; x
Lotion answered 17/2, 2013 at 23:49 Comment(4)
(+1), but a word of warning. Typing x = %+=% y/2 returns x = (x + y)/2. Adding parenthesis, i.e. x = %+=% (y/2) solves the problem.Foot
@Foot Why is that? I would've guessed division would be a higher precedence operator.Pentheam
@DavidKelley Not sure. I'm with you there. I ran into this issue working on a project once and it took me an hour to find the issue.Foot
Remember you're running a function, not doing an addition. Functions have the highest precedence so without the parenthesis it parses the y as the function input with the division being the next step down the chain. The parenthesis elevate the (y/2) operation to the top of the chain.Heptastich
S
37

R doesn't have a concept of increment operator (as for example ++ in C). However, it is not difficult to implement one yourself, for example:

inc <- function(x)
{
 eval.parent(substitute(x <- x + 1))
}

In that case you would call

x <- 10
inc(x)

However, it introduces function call overhead, so it's slower than typing x <- x + 1 yourself. If I'm not mistaken increment operator was introduced to make job for compiler easier, as it could convert the code to those machine language instructions directly.

Sufism answered 21/4, 2011 at 2:51 Comment(2)
This function cannot return the value and then increment like a postincrement ++. It's more similar to += or preincrement ++.Fallingout
Wrong! Incrementation wasn't introduced to make the job of compiler easier. INC instruction was introduced in processors primarily for implementing counters (cf. Intel Software Developer's Manual). I will update the answer.Proustite
R
27

R doesn't have these operations because (most) objects in R are immutable. They do not change. Typically, when it looks like you're modifying an object, you're actually modifying a copy.

Rooftop answered 21/4, 2011 at 3:14 Comment(2)
While immutability is a great/desirable property for objects (read: less bugs) I don't think immutability relates to the += question. In other languages += can be applied to immutable types (like strings in .net). The operation simply creates a new object and assigns the given variable to that new object. Immutability is maintained and the variable is updated.Thereunder
Good point. Immutability certainly makes this sort of operation less natural, however.Rooftop
S
15

Increment and decrement by 10.

require(Hmisc)
inc(x) <- 10 

dec(x) <- 10
Sirenasirenic answered 21/4, 2011 at 2:34 Comment(2)
These functions appear to have been removed from Hmisc as of version 4.1.0.Grisby
@Grisby looking at that notation, I cannot blame anyone.Hunsinger
A
9

We released a package, roperators, to help with this kind of thing. You can read more about it here: https://happylittlescripts.blogspot.com/2018/09/make-your-r-code-nicer-with-roperators.html

install.packages('roperators')
require(roperators)

x <- 1:3
x %+=% 1; x
x %-=% 3; x
y <- c('a', 'b', 'c')
y %+=% 'text'; y
y %-=% 'text'; y

# etc
Anissaanita answered 24/9, 2018 at 21:44 Comment(0)
D
7

We can override +. If unary + is used and its argument is itself an unary + call, then increment the relevant object in the calling environment.

`+` <- function(e1,e2){
  # if binary `+`, keep original behavior
  if(!missing(e2)) return(base::`+`(e1, e2))
  
  # if inner call isn't unary `+` called on language object,
  # keep original behavior
  inner_call <- substitute(e1)
  inner_call_is_plus_on_lng <-
    length(inner_call) == 2 &&
    identical(inner_call[[1]], quote(`+`)) &&
    is.language(inner_call[[2]])
  if(!inner_call_is_plus_on_lng) return(base::`+`(e1))
  
  eval.parent(substitute(X <- X + 1, list(X = inner_call[[2]])))
}

x <- 10

++x
x
#> [1] 11

other operations don't change :

x + 2
#> [1] 13
x ++ 2
#> [1] 13
+x
#> [1] 11
x
#> [1] 11

I can't really recommend it since you're messing with primitives which are optimised for a reason.

Darra answered 25/1, 2019 at 14:38 Comment(4)
I like this answer. but ++1 ==> " Error in 1 <- 1 + 1 : invalid (do_set) left-hand side to assignment" !Grantgranta
Thanks, I reworked the answer, now ++1 returns 1Darra
I think ++1 should return 2!Grantgranta
I don't think so, ++ is incrementing an object in place, it works only on symbols, 1 isn't a symbol, I can't change the value of 1, so what happens is that I fall back to the default behavior of +.Darra
P
1

We can also use inplace

library(inplace)
x <- 1
x %+<-% 2
Phosgene answered 25/10, 2020 at 22:31 Comment(0)
C
0

If you want to use i++ in an array to increment the index, you can try i <- i + 1, for example,

k = 0
a = 1:4
for (i in 1:4) 
    cat(a[k <- k + 1], " ")
# 1 2 3 4

but here <- can NOT be replaced with =, which does not update the index,

k = 0
a = 1:4
for (i in 1:4) 
    cat(a[k = k + 1], " ")
# 1 1 1 1

since = and <- are not always equivalent, as said in ?`<-`

Chance answered 16/3, 2021 at 7:31 Comment(0)
C
0

Here is a simpler approach to increment a variable.

inc = 1

for(i in 1:10){
    print(paste("Value of inc: ", inc))
    inc = sum(c(inc, 1))
}

You will get results as follows

[1] "Value of inc:  1"
[1] "Value of inc:  2"
[1] "Value of inc:  3"
[1] "Value of inc:  4"
[1] "Value of inc:  5"
[1] "Value of inc:  6"
[1] "Value of inc:  7"
[1] "Value of inc:  8"
[1] "Value of inc:  9"
[1] "Value of inc:  10"
Cacilie answered 6/3, 2023 at 18:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.