Check out R Golfing Tips on CGSE
Basics
Looping
The usual for(x in ...)
is usually used, but array manipulation is often used to golf bytes off. For example:
for(x in commandArgs(1))write(x*50,1)
write(commandArgs(1)*50,1,1)
Output
There are two ways to output, cat
and write
:
write(...,1)
cat(...,"
")
When outputting with paste0
to join a vector into a string by nothing:
write(paste0(vector),1)
cat(vector,"
",sep="")
If you are outputting three args to cat
, you can abuse the sep
function, but note only strings can be used in it and that x
and y
cannot be vectors and have to be strings or this won't work:
cat(x,"/",y,sep="")
cat(x,y,sep="/")
If statements
The if statements that are commonly used:
"if"(cond,x,y)
c(y,x)[1+(cond)]
"if" usually beats using vector indexing because you don't need to put >0
, and using a list requires turning the condition into an integer and adding 1 since R uses base 1-index vectors.
Vector indexing is occasionally used though in replacement of rep
. Say we want to print a string if a condition is true:
rep(str,cond)
str[cond]
Using []
will ensure that if the condition is true it will return the entire string and if not nothing. This works with multiple items too:
cat(paste0(rep(c("o",str),cond)))
cat(paste0(c("o",str)[cond]))
cat(c("o",str)[cond],sep="")
Builtins
R, as a statistical language, has tons of builtins and functions that are very useful when golfing. Here are some of them:
seq
diff
rle # Run Length Encoding
embed
gl # Generate factors by specifying the pattern of their levels
letters # 'a','b','c'...
LETTERS # 'A','B','C'...
month.abb # 'Jan','Feb','Mar'...
month.name # 'January','February','March'...
T # TRUE
F # FALSE
T
and F
are very powerful because you don't need to initialize a variable to 1 or 0 at the start of your code.
Aliases
We can define short aliases for functions using backticks for two arguments using primitive operators:
`+`=paste
x+y # paste(x,y)
(There is a way to define a short alias for functions with 3 or more arguments)
Coercion
Some examples of using coercion to avoid using long functions:
as.integer("19")
("19":1)[1]
el("19":1)
as.character(19)
paste(19)
outer
function
outer
is a fairly strong function. It takes the two arrays and applies a vectorized function. It acts like Julia's array manipulation feature:
x=1:3
println(x*x')
# [1 2 3; 2 4 6; 3 6 9]
In R:
x=1:3
write(outer(x,x,"*"),1)
# 1 2 3 2 4 6 3 6 9
You can place any operator or function (with quotes around it) in the third argument for outer
.
outer(X,Y,"*")
can also be rewritten as:
X%*%t(Y) # %*% is matrix vector multiplication
Or even better:
X%o%Y
rep()
alternatives
Even though rep()
is already fairly short, we can save a few more bytes by using :
and vector recycling.
Repeating n
zeroes (n>0
) - !1:n
or 0*1:n
instead of rep(0,n)
Repeating n
ones - !!1:n
instead of rep(1,n)
Repeating x
n
times - x+!1:n
instead of rep(x,n)
Using modular arithmetic to avoid each
args in rep
There aren't too many uses of this, but when you encounter one, you will probably need some creativity to come up with some "formula".
Generating the vector c(-1,-1,-1,0,0,0,1,1,1)
is easily done with rep(-1:1,e=3)
, but you can use modular arithmetic to save bytes:
-3:5%/%3
Random Tips
- Use
<-
instead of =
to remove brackets, so while(x<-...)
instead of while((x=...))
- Length of vector:
sum(v|1)
instead of length(x)
- Last element of vector:
tail(x,1)
instead of x[length(x)]
"if"
: "if"(x<y,7,9)
instead of if(x<y)7 else 9
el
to extract an item from a list with strsplit
: so el(strsplit(x,""))
instead of strsplit(x,"")[[1]]
- floor:
x%/%9
instead of floor(x/9)
Map
: Map(function,vector)
instead of sapply(vector,function)
Packers
3:1
eval(parse(t=intToUtf8(outer(utf8ToInt("..."),97:99,`%%`)+32)))
2:1
eval(parse(t=iconv("...",,"utf16")))