# 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

# Avoid Array#repeated_permutation and Array#repeated_combination

Credit to @AsoneTuhid who golfed the code for repeated permutations of length $$\\ge5\$$.

Some of Ruby's built-in methods have unfortunately long names. Never use Array#repeated_permutation or Array#repeated_combination; save bytes as follows.

### Repeated permutations

Assume a is an array. To get repeated permutations of length $$\L = n + 1\$$ of the elements of a:

a.product(a,a,a)  # L <= 4; number of arguments to product = n
a.product(*[a]*n) # L >= 5


Both of the above yield an array. To iterate over the permutations, simply call with a block.

### Repeated combinations

For repeated combinations of length $$\L\$$, use one of

a.send(a.methods[42],L)    # enumerator
[*a.send(a.methods[42],L)] # array


This trick of combining Object#send with Object#methods can be used to shorten calls to any method with a name 19 bytes or longer. (There are a few such methods in the base classes, though most are unlikely to be used in code golf.)

• 17 bytes – Asone Tuhid Jun 2 at 22:17
• @AsoneTuhid Very nice. Seems so obvious now that I see it. Thanks! – Dingus Jun 3 at 0:20

# << 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

# Save a byte when printing a word with symbols

This is a bit situational, but every byte counts!

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


# New features in Ruby 2.7 (experimental)

Ruby 2.7 is in prerelease (as of 17 Jun 2019) and has some features that look great for golfing. Note that some of them might not make it into the final 2.7 release.

All changes in Ruby 2.7-preview1: https://github.com/ruby/ruby/blob/v2_7_0_preview1/NEWS

### Numbered block parameters

This is my favorite. It lets you finally drop the |a,b| in a block:

%w[a b c].zip(1..) { puts @1 * @2 }
# => a
#    bb
#    ccc


### Method reference operator: .:

.: is syntactic sugar for the .method method, e.g.:

(1..5).map(&1r.:/)
# => [(1/1), (1/2), (1/3), (1/4), (1/5)]


### Pattern matching

I'm not sure how much use this will see in golf, but it's a great feature for which I only have a contrived example:

def div(*a)
case a
in [0, 0] then nil
in [x, 0] if x > 0 then Float::INFINITY
in [x, 0] then -Float::INFINITY
in [x, y] then x.fdiv(y)
end
end

div(-3, 0) # => -Infinity


The pattern matching syntax has lots of features. For a complete list, check out this presentation: https://speakerdeck.com/k_tsj/pattern-matching-new-feature-in-ruby-2-dot-7

This is also the feature most likely to change before 2.7 is finished; it even prints a warning when you try to use it, which you should heed:

warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!

### Beginless Range: ..3

Analogous to the endless Range introduced in 2.6, it may or may not have much use in golfing:

%w[a v o c a d o].grep(..?m)
# => ["a", "c", "a", "d"]


### Enumerable#tally to count like elements

This could be useful in golfing:

%w[a v o c a d o].tally
# => {"a"=>2, "v"=>1, "o"=>2, "c"=>1, "d"=>1}


### Enumerable#filter_map to filter+map in one

(1..20).filter_map {|i| 10 * i if i.even? }
# => [20, 40, 60, 80, 100]


If the block returns nil or false the element will be omitted from the result.

### Integer#[] takes a second argument or range:

You've long been able to get a specific bit from an integer with with subscript notation:

n = 77 # (binary 01001101)
n[3] # => 1


Now you can get the value of a range of bits by a second length argument or a range.

n = 0b01001101
n[2, 4] # => 3 (0011)
n[2..5] # => 3


Note that bits are indexed from least- to most-significant (right to left).

• The range in the Enumerable#filter_map example should be (1..10), I think? – Dingus May 1 at 1:46
• The method reference operator didn't make it in, as I sadly discovered just now trying to use it to do a restricted source challenge. – histocrat Jun 6 at 17:32

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

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)

## 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

# 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 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. ## 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)  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. 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. 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