# Tips for golfing in Ruby

What general tips can you give for golfing in Ruby?

I'm looking for ideas that can be applied to code golf problems in general that are specific to Ruby. (For example, "Remove comments" would not be an answer.)

• Someone needs to write a language called Rub, which uses a single Unicode character for every Ruby token, kinda like Jelly and Pyth :) – Mark Thomas Aug 30 '17 at 12:28

# Re(ab)use predefined globals

There is a whole bunch of predefined global variables that you can use instead of initialising new variables.

A very common example is that you have some golfed one-liner that loops, but you also need to keep a counter for later:

i=0
s.gsub!(/../){i+=1;"foo"}while s=~/.../
p i


So frustrating. Luckily, $. comes to the rescue! It is initially 0, and is incremented each time you read a line from input. This is of course incredibly useful if you actually need to keep track of the amount of lines you have read, but otherwise you can just manually update it: s.gsub!(/../){$.+=1;"foo"}while s=~/.../
p$.  That's 3 bytes saved. If you for example need to append your counter to a string s, you may save some more bytes though string interpolation because the variable has a sigil: i=0;i+=1;s+i.to_s i=0;i+=1;s+"#{i}"$.+=1;s+"#$."  Another interesting global is $:. It's an alias for $LOAD_PATH and is an array full of strings. I haven't actually used this in a golf yet, but I imagine it could come in handy if you need a cache for checking previously visited values or something, and don't care if it's completely empty. Your values are unlikely to crash with any of its initial contents anyways. • Especially for new golfers, it's worth noting that you generally can't use $. as a counter like this in function submissions because of this consensus regarding function reuse. (I was guilty of doing so a couple of times before I became aware of that rule.) – Dingus Sep 16 '20 at 14:21

# Subscripting Numbers!

I just discovered this yesterday. n[i] returns n's bit at the i-th position. Example:

irb(main):001:0> n = 0b11010010
=> 210
irb(main):002:0> n[0]
=> 0
irb(main):003:0> n[1]
=> 1
irb(main):004:0> n[2]
=> 0
irb(main):005:0> n[3]
=> 0
irb(main):006:0> n[4]
=> 1
irb(main):007:0> n[5]
=> 0


# Save a byte when printing a word with symbols

This is a bit situational, but every byte counts!

puts"thing" # before
puts:thing  # after
^


If the first line starts with #! and contains ruby, then Ruby will take command-line switches from it.

For example, if you require two libraries, you can golf

require'benchmark'
require'prime'


into

#!ruby -rbenchmark -rprime


which saves 7 bytes.

• Or you can just add -rbenchmark -rprime to the character/byte count. That's usual in choice golf. – nyuszika7h Jul 5 '14 at 12:21

# << trick

a.push x


can be shortened to:

a<<x


for -4 bytes.

• Note: this also works for Strings – Cyoce Nov 4 '16 at 1:13

To subtract one (-1), instead of doing this

(i - 1) * 2


do the following

~-i * 2


which will save you 2 bytes in cases where you otherwise have to use brackets (e.g. arithmetics).

• like wise, (i+1) can become -~i – Cyoce Nov 4 '16 at 1:16

# Array#assoc/rassoc

When you have an array of arrays and want to find the sub-array that starts with a particular value, don't use Enumerable#find, use Array#assoc:

a = [[0,"foo"],[0,"bar"],[1,"baz"],[0,"qux"]]
a.find{|x,|x==1} # => [1,"baz"]
a.assoc(1) # => [1,"baz"]


This is also a good replacement for Enumerable#any? in some situations.

Array#rassoc does the same thing, but checks the sub-arrays' last element:

a = [[123,"good"],[456,"good"]]

• For the a.any? line in the rassoc  example, what does |x,| do? How is it different from |x|? – Cyoce Nov 4 '16 at 1:05
• @Cyoce Block parameter destructuring follows the same rules as destructuring assignment, so it's like x=[1,2] vs x,=[1,2]. Using my example above, with |x|, in the first iteration x will be [0,"foo"]. With |x,y|, x will be 0 and y will be "foo". Likewise, with |x,|, x will be 0. In other words, it says "put the first element in x and throw the rest away. – Jordan Nov 4 '16 at 1:27
• Note that it doesn't work in reverse, e.g. |,y| is a SyntaxError, ergo |_,y|. But I've just now realized that |*,y| works, which is cleaner than using a variable named _ (but no shorter). – Jordan Nov 4 '16 at 1:39

## Fun with arrays

There are many ways to do the same thing in ruby, and often times the default methods are inefficient - as a case study, a new arrays with set size and initialized to all 10:

Array.new(20,10) # idiomatic
[10]*20


You may already be informed not to use this syntax, however, when you are initializing elements in an array that needs to not be shallow-cloned, for example 2D arrays:

[[]]*20               # beware, all 20 elements points to the one same array
Array.new(20){[]}     # idiomatic
20.times.map{[]}
([0]*20).map{[]}      # free ticket, you can move any line into 0 to save newline
([a,b,c,d]*5).map{[]} # saves a char when you move 4 1-time use expressions
(1..20).map{[]}


Many operations in ruby will create new objects. Sometimes this is to our advantage. For example, to create a new array with the same size as another array, we can get by without even knowing its .size at all:

[0]*a.size # looks kinda nice
a.map{0}   # -2 chars


(Note: the []* version may be preferable in cases where you also want to reuse the value, so [0]*b=a.size might end up helping you cut a char elsewhere)

To shallow clone an array:

b=a[0..-1] # makes sense
b=a.clone
b=a*1      # this returns new_ary
b=*a       # this version for assignments - use [*a] in expressions

• .clone is an alias of .dup ([*a] is still better for arrays) – Asone Tuhid Mar 1 '18 at 12:13

# Use eval instead of reduce

While array.sum is great and shorter than array.reduce(:+), there are no similar methods for the other operators *, -, / ...

Joining arrays and evaling them saves some space:

a = [1,2,3,4]

a.reduce(:*)   # => 24
eval(a*?*)     # => 24
^^   two bytes saved.


It also removes the need to map string input to numbers first:

b = "1 2 3 4".split

b.map(&:to_i).reduce(:*)
eval(b*?*)
^^^^^^^^^^^^^^

• eval a*?* to save another char. – Unihedron Jan 29 '18 at 6:31
• also for case 2, using .tr' ',?* is way more concise than .split*?*... – Unihedron Jan 29 '18 at 6:33
• also, note that a.reduce:* is valid if brackets aren't required though I think it can always be replaced with eval a*?* – Asone Tuhid Mar 1 '18 at 12:10
• eval(a*?*) is horrible. I like it! – Eric Duminil Oct 10 '20 at 16:31

# New features in Ruby 2.5 and 2.6

Ruby keeps getting new features that look like they could be handy for golfing. Here are some that caught my eye. If there's any you think should be added feel free to edit or mention them in the comments.

## Ruby 2.5

Here's an easy-to-read reference with all of the new features in Ruby 2.5: https://rubyreferences.github.io/rubychanges/2.5.html

## Regexp absence operator: (?~foo)

This matches any string that doesn't end with foo. I don't have a specific use for this one off the top of my head, but here's a good article about it.

### Enumerable#all?, any?, none?, and one? accept objects that respond to ===

Similar to Enumerable#grep:

%w[Foo bar].one?(/[A-Z]/) # => true
%w[Foo bar].any?("bar") # => true
[1, 2, 3, 5, 7, 11].all?(0..10) # => false


### Hash#slice gets a subset of a Hash

I don't see a lot of Hashes in Ruby golf, but it might come in handy:

{foo: 1, bar: 2, baz: 3}.slice(:bar, :baz) # => {foo: 1, bar: 2}


## Ruby 2.6

All of the changes in Ruby 2.6: https://rubyreferences.github.io/rubychanges/2.6.html

### Endless Range: 1..

Lots of potential uses for this.

%w[a b c].zip("X"..).to_a
# => [["a", "X"], ["b", "Y"], ["c", "Z"]]

[1, 2, 3, 5, 7, 11].any?(10..)
# => true


### String#split takes a block

Saves four bytes when iterating over the result of String#split, e.g.:

"foo;bar;baz".split(?;).map {|s| x << s.upcase if ... }


You can do this:

"foo;bar;baz".split(?;) {|s| x << s.upcase if ... }


Note that it still returns the original string, so it won't always be fewer bytes than map.

### Proc composition with >> and <<

Procs now have >> and << methods that let them be combined with other procs, or any object that responds to call:

double = ->n{ n * 2 }
square = ->n{ n ** 2 }
(double >> square)[5] # => 100
(double << square)[5] # => 50


### % operator for Range

An alias for Range#step:

((1..10) % 2).to_a
# => [1, 3, 5, 7, 9]


### Random.bytes

Could be handy.

Random.bytes(10)
# => "'\xB2\xD7\ny"


When getting input of fixed length the optional integer parameter to gets may come in handy.

• Getting a substring:

gets 10 vs gets[0,10] -- saves 3 bytes

• Cutting trailing newline:

gets 10 vs gets.chop -- saves 3 - log10(required_length) bytes (= 2 in this case)

## Cloning strings

Strings are mutable in Ruby so if you have two variables holding the same string (a=b="string") and you modify one (a[0]="S"), the other will also change (b=="String")

To clone a string:

a="string"

b=a.clone # 9 bytes
b=a.dup # 7 bytes
b=+-a # 5 bytes
b=-a # 4 bytes (b will be frozen)

• b=a*1 is yet another way. – vrintle Dec 12 '20 at 10:18

When working with arrays, .compact can be replaced with -[nil] to save 2 chars.

• -[p] saves another 2. – Doorknob Aug 25 '18 at 16:12

# Is it an array?

Originally from histocrat.

Rather than writing

a.class==Array  # 14 bytes


you could write

a.is_a? Array   # 13 bytes


or even

a!=[*a]         # 7 bytes


# Use ~// and !// to match against $_ (last line read) These can be used with the -n or -p flags. ~/regex/ is equivalent to $_=~/regex/ returning the index of the first match or nil.

Try it online!

!/regex/ equivalent to _!~/regex/ returning true or false. Try it online! ### Note that !// is weird as it doesn't call the ! method on the regex but only if you use a literal. !/regex/ matches the expression. r=/regex/;!r calls the ! (not) method and always returns false. Also, !r=/regex/ gives an assignment in conditional warning so there's some syntactic sugar going on. • To generate symmetric output, you can use a single range like (-x..x) and then map a function on the absolute value: (-8..8).map{|x|x.abs} • Use short-circuit evaluation of boolean expressions to avoid if...else: x>1&&s+=x • To check if an integer array a contains a number x, you can use a-[x]!=a, especially useful if x is an expression. • Defining a variable as an accumulator is often shorter than using map and then reduce. • Use string interpolation with % for alignment: "x%12s"%?x is shorter than ?x+11*" "+?x or for base conversions: "%b"%65 vs 65.to_s(2) • Use complex number for trigonometric functions: -1.argis PI, 1i.arg is PI/2, (a+b*1i).arg is Math.atan(b/a) and works even when a and b are integers. To check if a is an Array, instead of doing: a.kind_of?(Array)  you can do a.to_s['[']  Won't work if a can be a string that contains [. • Or use the triple equals thing: Array===a ;) – daniero Jun 26 '15 at 23:33 • How about a==[*a]? – histocrat Nov 4 '16 at 1:23 ## Default function arguments Pre-defining your variables within a function can save you from calling particular arguments if you already know what they are and are calling the function multiple times. def f(a,b,c) return a+b+c end puts f(f(3,3,3),f(3,3,3),f(3,3,3)) # => 27  One can shorten this quite easily: def f(a,b=3,c=3) return a+b+c end puts f(f(3),f(3),f(3)) # => 27  If you do not assign any second or third arguments, then b=3 and c=3 automatically. One can shorten this further: def f(a,b=a,c=a) return a+b+c end puts f(f(3)) # => 27  Note however that you'll need to give it at least one variable, the first one, and I'm not quite sure how you can avoid assigning a value to b while assigning a value to c. See here for more argument methods. String split function uses ; or space by default; if input is space-seperated, you can omit the argument.

# Reads 3 integers from line 1 of input file
x,y,z=gets.split.map &:to_i


Or, you can configure the behaviour of ARGF with $/ (if there is only one line): # Reads 3 integers from input file # Not seperated by newlines, so in case of: # 1 2 # 3 4 # You will get: 1 2 4 ("2\n3".to_i -> 2)$/=' '
x,y,z=$<.map &:to_i  Due to the predictable behaviour of .to_i / .to_f, if you only have two numbers, you can use string.to_i(/.to_f) to get the first number and substring after the non-digit (even simpler for space) for the two values. There are tricks if you already know the constraints on the length of the numbers and especially so if the first one is length 1-2: v=gets # 1 2 / 11 22 / 11 22222222222222222222 / 123 4567890123456 v.to_i # 1* 11* 11* 123* v[2,9].to_i # 2*#$  22*#$22222222 3 v[2,99].to_i # 2#$   22#$22222222222222222222*# 3 v[2..-1].to_i # 2# 22# 22222222222222222222*# 3 v[/\d+$/].to_i   # 2     22      22222222222222222222      4567890123456
v[~/ /,9].to_i   # 2$22$     22222222                  45678901
v[~/ /,99].to_i  # 2     22      22222222                  4567890123456*
v[~/ /..-1].to_i # 2     22      22222222                  4567890123456

*: recommend to use in cases as specific than this
#: 1st int in string length is expected to be <=2 (-10 < x < 100)
$: 2nd int in string length is expected to be <=8 (if 1st int is length 1: <=9) Note: [x,99] will take 99 characters, while ..-1 goes all the way to end of string. Because ~/ / matches the index of the space, this should be accounted for: [~/ /,9] will get length 8 int at most, as first char is the space Note: If there are three+ numbers, please just use split or map The above trick can be combined with $_:

p *gets.to_i..$_[2,9].to_i  Handy ways to repeat strings: # aaaaabcbcbcbcaaaaa,aaaaa,aaaaa$><<?a*5+'bc'*4+[?a*5]*3*?,


Shorthand for size of input line:

p (eval gets.chars*?+)/~/$/ # is equivalent to: p (eval gets.chars*?+)/$_.size


The <=> (spaceship) operator compares two expressions and returns -1, 0, or 1. Applies to anything that can be compared with <, >, and ==.

Some example uses:

x<=>0 is equivalent to the sign function.

x.*x<=>0 is the absolute value of x.

# Filtering a specific class from an Array

Suppose, you've to choose only Integer from

a = [1, 2, "3", 4.0, [5], "6".to_sym, 7r]


then you can do,

a.keep_if{|x|x.kind_of? Integer} # 32 bytes
a.keep_if{|x|x.is_a? Integer} # 29 bytes
a.select{|x|x.is_a? Integer} # 28 bytes
a.select{|x|Integer===x} # 24 bytes
a.grep(Integer) # 15 bytes


Try it online!

You can use Numeric class in case you want numbers only.

Quick way to check if all items in a Ruby array are unique lists various ways to check whether everything in an array is unique. Unfortunately, none of them are methods that I can send to a receiver, I need to have my array on both sides of an operator. Lame!

Fortunately, uniq! returns nil if no changes are made, and returns the modified array if changes are made, meaning that it can be placed at the end of a pipeline to check for uniqueness;

x.method1.method2.method3.uniq! ? "not unique" : "everything is unique!"

Various other shouty methods have similar behaviour - returning the modified array if changes are made and nil if no changes are made.