Ruby Golf Cheatsheet
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
enddef 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” }