Ruby Golf Cheatsheet

Andrew Brown
Ruby Golf
Published in
5 min readJan 16, 2016

A handy cheatsheet to make your way down when you’re in the final stages of a golf challenge looking to shave off those last few characters.

This is a living document and I’ll be updating it as time goes on.

Looping

  • Don’t loop over arrays with .each. You can shave a character off by using .map instead.
  • n.times { } is almost always shorter than 1.upto(n), except for when you need to call .to_i on n (then upto becomes shorter, because it can take a string). Sometimes .map can be even shorter.
  • If you’re looping or recursing in a single direction and have a guard clause returning if a value is equal to some sentinel, you can shave a character off by switching from equality to inequality comparison.
return if i == 0
return if i < 1
  • Reuse your loops when you can by bunging everything into a single array and operating based on value or type.
["a", "b", 2, 4].map { |e| e.to_s==e ? e.upcase : e * 2 }
=> ["A", "B", 4, 8]
  • If you want to loop over a value that can be a scalar or array, you can use the splat operator to treat both types identically: the scalar becomes an array containing only it:
[*items].each {|item| ... }

Variables and values

  • The numbers 100 to 126 can be written as ?d to ?~.
  • Use scientific notation for large numbers. 1e4 is shorter than 10000.
  • Single-character strings can be prefixed with a ? instead of quoting them, e.g. ?x instead of “x” and ?? instead of “?”. ?\n and ?\t also work.
  • Use 1 or !p for true. Use p (which returns nil) or !0 for false.

String manipulation

  • Use [] to check if a string contains another.
‘foo’[‘f’] #=> ‘f’
  • Use tr instead of gsub for character-wise substitutions.
‘01011’.tr(‘01’,’AB’) #=> ‘ABABB’
  • When using gsub, use the \1 escape characters instead of a block. Don’t forget you can re-use them outside of the gsub once they’re set, too.
"golf=great short=awesome".gsub(/(\w+)=(\w+)/,'(\1~>\2)')"golf=great short=awesome".gsub(/(\w+)=(\w+)/){"(#{$1}~>#{$2})")
  • If you need to remove trailing newlines, use chop instead of chomp.
  • Replace .to_s with direct string interpolation, e.g. “#{n+10}”.
  • When you’re using string interpolation, you can omit the curly braces if your variable name has a sigil ($, @) in front of it. Very useful for special variables.
puts "this program has read #$. lines of input"

Array manipulation

  • Use the splat operator to get the head and tail of an array, or vice versa.
tail, *head = [1,2,3]
tail => 1
head => [2,3]
// or*head, tail = [1,2,3]
head => [1,2]
tail => 3
  • Use the * operator on arrays to join them.
[1,2,3] * ?,
=> "1,2,3"
  • Replace .compact with -[nil] or -[p]. Replace .reject(&:zero?) with -[0].
  • If you’re assigning a variable to the first element in an array, a, = c is shorter than a = c[0].
  • If you’re assigning an array with one scalar element in it, *a = 0 is shorter than a = [0].
  • To check array length without .length, you can instead check if the array has anything at a given index. If you grab past the last index you will get nil, a falsey value. Note: this won’t work if you have falsey values (false, nil) in the array already.
if !a[4] # equivalent to: if a.length < 5
  • When casting to an array, use [*(…)] instead of (…).to_a. This also applies to ranges for easy consecutive-number arrays, e.g. x = [*0..5].
  • Sum an array’s contents with .inject :+, e.g. [1, 2, 3].inject :+.

Hash manipulation

  • You can turn a one-dimensional array into a hash with Hash.
fruit = ["apple", "red", "banana", "yellow"]
=> ["apple", "red", "banana", "yellow"]

Hash[*fruit]
=> {"apple"=>"red", "banana"=>"yellow"}

Control flow

  • Use abort to terminate the program and print a string to STDERR — shorter than puts followed by exit
  • Use procs over functions whenever possible. Call the proc with c[n].
# 28 characters
def c n
/(\d)\1/=~n.to_s
end

# 23 characters, saves 5
c=->n{/(\d)\1/=~n.to_s}
  • If you have return if some_condition clauses at the top of your function, you can drop the return and turn the whole method into a ternary. If the rest of the function can be expressed in a single line, you can avoid wrapping it in parentheses.
def method x
return if x < 5
y = x * 5
y * 2
end
def method x
x < 5 ? nil : (
y = x * 5
y * 2
)
end

I/O

  • If you read a line with gets, you can then use ~/$/ to find its length (this doesn’t count a trailing newline if it exists)

Special variables

$!   # The exception object passed to #raise.
$@ # The stack backtrace generated by the last exception raised.
$& # Depends on $~. The string matched by the last successful
match.
$` # Depends on $~. The string to the left of the last successful
match.
$' # Depends on $~. The string to the right of the last successful
match.
$+ # Depends on $~. The highest group matched by the last
successful match.
$1 # Depends on $~. The Nth group of the last successful match.
May be > 1.
$~ # The MatchData instance of the last match. Thread and scope
local. MAGIC
$= # The flag for case insensitive. Defaults to nil. Deprecated.
$/ # The input record separator (eg #gets). Defaults to newline.
$\ # The output record separator (eg #print and IO#write). Default
is nil.
$, # The output field separator for the print and Array#join.
Defaults to nil.
$; # The default separator for String#split. See -F flag.
$. # The current line number of the last file from input.
$< # Same as ARGF.
$> # The default output for print, printf. Defaults to $stdout.
$_ # The last input line of string by gets or readline. Thread and
scope local.
$0 # Contains the name of the script being executed. May be
assignable.
$* # Same as ARGV.
$$ # The process number of the Ruby running this script. Read
only.
$? # The status of the last executed child process. Read only.
Thread local.
$: # Same as $LOAD_PATH.
$" # The array contains the module names loaded by require.
$-0 # See $/.
$-a # Autosplit mode. True if option -a is set. Read-only variable.
$-d # Same as $DEBUG.
$-F # See $;.
$-i # In in-place-edit mode, this variable holds the extension, otherwise nil.
$-I # Same as $LOAD_PATH.
$-l # True if option -l is set. Read-only.
$-p # True if option -p is set. Read-only.
$-v # Same as $VERBOSE.
$-w # True if option -w is set.

Dates

require 'date'; z = Date::DAYNAMES

is much shorter than

%w(Sun Mon Tues Wednes Thurs Fri Satur).map { |p| “#{p}day” }

--

--