Le Carnet De Theo Et Julien

The Ultimate Guide to Ruby golfing

Basics

Find out our page dedicated to golfing basics with Ruby →

Golfing basics in Ruby

Catch the Input

Using dd instead of gets can save you 1 space if there’s only 1 input (equivalent to $stdin.read or $<.read)

puts`dd`
# vs
puts gets

n=eval`dd`
# vs
n=gets.to_i

We can also use sed to ignore first line

puts`sed 1d`
# vs
gets;puts $<.read

We can map the whole input at once with $<

n,a,b=$<.map &:to_i
# vs
n=gets.to_i
a=gets.to_i
b=gets.to_i

Use the wildcard to directly use $<

a,b,c=*$<
# vs
a,b,c=$<.map{_1}
a,b,c=$<.to_a

Using gets can allow you to remove the first element of $<

gets;d=$<.map &:chars
# vs
d=$<.map(&:chars)[1..]

$_ store the last read line with gets, it may not be assigned

gets;puts (1..10).map{$_.to_i*_1}
# vs
n=gets.to_i;puts (1..10).map{n*_1}

 

How to print

Use p to print Integers or Booleans

p 1
# vs
puts 1

Use p * to print all the elements of Integers or Booleans array

a=[1,2,3]

p *a
# vs
puts a

Use $><< to print without line break

$><<a
# vs
print a

# !! watch out precedence of the operator <<
$><<(a?'a':'b')
# vs
print a?'a':'b'

 

Arrays

Square brackets are not necessary to initialize an array with more than 2 elements

d=1,2
# vs
d=[1,2]

To initialize an array of one element, we can use the splat operator

*d=1
# vs
d=[1]

Use map to iterate over an array (watch out if performance is required)

a.map{}
# vs
a.each{}

Use [*..] to convert ranges into arrays rather than .to_a method.

d=*1..10
# vs
d=(1..10).to_a

.product generates all possible combinations of an array

d=1,2,3
d.product d
# => [[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]

Use * operator rather than .join

a=1,2,3

puts a*" "
# vs
puts a.join" "

puts a*""
# vs
puts a.join

.each_cons allows to generate all sub-arrays of n consecutive elements

d=*1..10
d.each_cons(3).to_a
# => [[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], 
#     [5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]]

.each_slice allows to slice an array into sub-array of n elements

d=*1..10
d.each_slice(3).to_a
# => [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]

Use eval rather than .reduce on simple operations

d=1,2,3,4
p eval d*?*
# vs
p d.reduce :*

Uniq values in an array

[0,1,1,3,3,3,2]|[] # => [0, 1, 3, 2]
# vs
[0,1,1,3,3,3,2].uniq # => [0, 1, 3, 2]

a=0,1,1,3,3,3,2

a&a
# vs
a|[]
# vs
a.uniq

tally?!? Count the occurrences of each element of an Enumerable

%w'a b d a b a a a z'.tally
# vs
%w'a b d a b a a a z'.reduce(Hash.new 0){_1[_2]+=1;_1}
%w'a b d a b a a a z'.group_by{_1}.map{[_1,_2.size]}.to_h
%w'a b d a b a a a z'.group_by{_1}.transform_values &:size

# => {"a"=>5, "b"=>2, "d"=>1, "z"=>1}

Matrix transposition

m=[1,2],[3,4],[5,6],[7,8]

m.transpose
# vs
...very long

# => [[1, 3, 5, 7], [2, 4, 6, 8]]

Use (a..b) rather than (a..b-1)

Use flat_map rather than flatten and map

 

String

Initialize a one character string

c=?c
# vs
c='c'

Use .split without arguments

"Hello, world!".split # => ["Hello,", "world!"]
# vs
"Hello, world!".split(' ') => ["Hello,", "world!"]

Be aware of some subtleties of .split

"a b\nc d".split # => ["a", "b", "c", "d"]
# vs
"a b\nc d".split(' ') # => ["a", "b", "c", "d"]
# vs
"a b\nc d".split(/ /) # => ["a", "b\nc", "d"]

.bytes allows to work directly on ASCII values

"abcdefghi".bytes
# vs
"abcdefghi".chars.map(&:ord)

Using Regex is often shorter than empirical method

"AbCdEfGhIjKlMnOpQrStUvWxYz".scan /[A-Z]/
# vs
"AbCdEfGhIjKlMnOpQrStUvWxYz".chars.select{_1==_1.upcase}

%w() allows to init an array of multiple String

%w(one two three)
# vs
["one","two","three"]

.next allows to increment over alphanum of a String (especially usefull for the hours)

"12:24".succ # => "12:25"

.tr allows to translate a list of Char into another

"hello, world!".tr("lo","10") # => "he110, w0r1d"

.tr is also shorter than .delete to remove Chars

"hello, world!".tr("lo","") # => "he, wrd"
# vs
"hello, world!".delete("lo") # => "he, wrd"

We can test if a String contains a subString with the operator []

string["substring"]  # renvoie "substring" ou nil
# vs
string.include?('substring')

We can use the same operator to do a sub

string["substring"]='sub'
# vs
string.sub("substring",'sub')

Position of letters in the Alphabet

a=?a.ord # 97
A=?A.ord # 65

p a-97 # => 0
p A-65 # => 0
p a%32 # => 1
p A%32 # => 1

We can use an array to concatenate numbers

a=1
b=2

[a,b]*' '
# vs
"#{a} #{b}"
a.to_s+" "+b.to_s

 

Others

Reach the limits of the ruby interpreter!

a=2

a<2?3:5 # => 5
# vs
2>a?3:5 # => Syntax error
# vs
2>a ?3:5 # => 5
a=2

a>1?:OK:'Not OK' # => OK
# vs
a<2?'Not OK'::OK # => Syntax error
# vs
a<2?'Not OK':'OK' # => OK
p$.
# vs
p $.

'abcd'.tr'a-d','1-4'
# vs
'abcd'.tr('a-d','1-4')

When possible values are limited, it’s usually possible to use inequality rather than equality.

a%10<1
# vs
a%10==0

.digits allows to generate an array of numbers in any base

13.digits # => [3,1]

57.digits 9 # => [3,6]

Some variables are predefined in Ruby, it’s possible to use them to avoid declaring a new one.

# print diagonal of input
$<.map{$><<_1[$.-1]}
# vs
i=-1;$<.map{$><<_1[i+=1]}

Use the spaceship operator <=> to index an array

puts %w"a_égal_b a_plus_grand_que_b a_plus_petit_que_b"[a<=>b]
puts ["a égal b","a plus grand que b","a plus petit que b"][a<=>b]
# vs
puts a<b ?"a plus petit que b":a>b ?"a plus grand que b":"a égal b"

In the same way, it’s possible to use formulas as an index of an array rather than conditions

a=gets.to_i

a*[3,5][a%2]
# vs
a*(a%2<1?3:5)

(?1..?9) to avoid using .to_s in the range

# count number of each digits in given string
s=gets

(?0..?9).map{s.count _1}
# vs
(0..9).map{s.count _1.to_s}

The % operator on a range allows to add a step

d=*(1..9)%2
# vs
d=*1.step(9,2)
# vs
d=(1..9).filter{_1%2>0}

# => [1, 3, 5, 7, 9]

The captures of the last Regex is stored in the variable $~. We can access the elements $~[1] directly with $1, $~[2] with $2$~[0] is the whole match

We can use the implementation of the negative numbers and the priority of the unary operators to save some more Char (man Two’s Complements)

~-a == a-1
-~a == a+1

We can assign multiple variables at once by chaining the assignations

a=b=c=d=0
# vs
a=0
b=0
c=0
d=0

permutation = how many different combinations AND orders are possible

combination = how many different combination are possible

https://codegolf.stackexchange.com/questions/363/tips-for-golfing-in-ruby