63
21
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.)
Please post one tip per answer.
63
21
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.)
Please post one tip per answer.
49
?d to ?~ in 1.8.$><<"string" is shorter than print"string".$<.map{|l|...} is shorter than while l=gets;...;end. Also you can use $<.read to read it all at once.$< and gets will read from a file instead of stdin if the filename is in ARGV. So the golfiest way to reimplement cat would be: $><<$<.read.8An even golfier way to implement cat is to leave the ruby file completely empty (0 bytes) and insist that it should be run from the command line with the -p flag. – daniero – 2013-07-17T20:01:02.600
1So in 1.8, all I have to do is go ?~ and it will return 126? – Simply Beautiful Art – 2017-05-13T13:09:30.097
5You can go beyond 126 using thinks like ☺ or ♫, or if you are crazy enough: ?﷽.ord=65021 – Simply Beautiful Art – 2017-05-13T15:45:55.063
@SimplyBeautifulArt Your username checks out so well for this one. – val says Reinstate Monica – 2019-10-26T15:45:42.417
1?x yields the ascii code in general, so you can realistically get all the printables to digits in two characters. 1.9 is different, 'a'.ord yields the ascii number, but is four bytes longer than the decimal version. – Hiato – 2011-02-03T08:03:17.097
You can use ?a.ord in 1.9, but that's still longer than the decimal. – Nemo157 – 2011-02-03T22:59:06.487
32
Use the splat operator to get the tail and head of an array:
head, *tail = [1,2,3]
head => 1
tail => [2,3]
This also works the other way:
*head, tail = [1,2,3]
head => [1,2]
tail => 3
Use the * method with a string on an array to join elements:
[1,2,3]*?,
=> "1,2,3"
28
abort to terminate the program and print a string to STDERR - shorter than puts followed by exitgets, you can then use ~/$/ to find its length (this doesn't count a trailing newline if it exists)[] to check if a string contains another: 'foo'['f'] #=> 'f'tr instead of gsub for character-wise substitutions: '01011'.tr('01','AB') #=> 'ABABB'chop instead of chompPlease explain how to use ~/$/ – Mathieu CAROFF – 2018-11-25T06:47:21.750
@MathieuCAROFF every time you call gets, its result is stored in the $_ variable. /regex/ ~= string returns the index of the first match. Calling ~ on a regex is equivalent to /regex/ ~= $_. So it would be something like s=gets;l= ~/$/ – Cyoce – 2019-02-08T03:18:03.193
2+1 for abort and ~/$/ – J-_-L – 2011-06-26T22:13:33.527
20
end.Try to remove end from your code.
Don't use def...end to define functions. Make a lambda with the new -> operator in Ruby 1.9. (The -> operator is a "stabby lambda", or "dash rocket".) This saves 5 characters per function.
# 28 characters
def c n
/(\d)\1/=~n.to_s
end
# 23 characters, saves 5
c=->n{/(\d)\1/=~n.to_s}
Method calls are c n or c(n). Lambda calls are c[n]. Changing each c n to c[n] costs 1 character, so if you can use c n more than 5 times, then keep the method.
All methods that take do...end blocks can take {...} blocks instead. This saves 3 to 5 characters. If the precedence of {...} is too high, then use parentheses to fix it.
# 48 characters
(?a..?m).zip (1..5).cycle do|a|puts a.join','end
# WRONG: passes block to cycle, not zip
(?a..?m).zip (1..5).cycle{|a|puts a.join','}
# 45 characters, saves 3
(?a..?m).zip((1..5).cycle){|a|puts a.join','}
Replace if...else...end with the ternary operator ?:. If a branch has two or more statements, wrap them in parentheses.
# 67 characters
if a<b
puts'statement 1'
puts'statement 2'else
puts'statement 3'end
# 62 characters, saves 5
a<b ?(puts'statement 1'
puts'statement 2'):(puts'statement 3')
You probably don't have while or until loops, but if you do, then write them in modifier form.
(a+=1
b-=1)while a<b
Are the parentheses around puts'statement 3' necessary? – Cyoce – 2016-12-02T02:38:06.560
15
Addition to w0lf
When working with arrays,
.compactcan be replaced with-[nil]to save 2 chars.
Combined with above -> you can make it even shorter with -[p] to save another 2 chars.
14
Use the short predefined variables wherever possible, e.g. $* instead of ARGV. There's a good list of them here, along with a lot of other useful information.
12
When you are using string interpolation, (as you should pr Martin Büttner's post), you don't need the curly brackets if your object has a sigil ($, @) in front of it. Useful for magical variables like $_, $&, $1 etc:
puts "this program has read #$. lines of input"
So also if you need to print a variable more than you use it otherwise, you may save some bytes.
a=42; puts "here is a: #{a}"; puts "here is a again: #{a}"
$b=43; puts "here is b: #$b"; puts "here is b again: #$b"
11
If you need to find if a particular element e is inside a range r, you can use
r===e
instead of the longer:
r.cover?(e) # only works if `r.exclude_end?` is false
or
r.member?(e)
or
r.include?(e)
3Isn’t r===e even shorter? – akuhn – 2012-06-01T21:10:55.447
@akuhn Yes, it is. Much Shorter. Thanks for pointing that out, it helped me shorten my code by 10 chars, which is huge: http://codegolf.stackexchange.com/a/6125/3527
– Cristian Lupascu – 2012-06-01T21:20:33.0871You’re welcome. Everything that can be used in a switch statement has === implemented. – akuhn – 2012-06-02T12:49:34.670
10
Don't use the true and false keywords.
Use:
!p for true (thanks, histocrat!)!0 for false. If all you need is a falsy value, then you can simply use p (which returns nil).to save some chars.
1Unless you actually need true (i.e. if a truthy value is enough, like in an if condition), you don't even need !!. – Martin Ender – 2014-08-06T06:31:37.650
4And similarly, p (which evaluates to nil) is a shorter falsey value. Which means the shortest way to get true is !p. – histocrat – 2014-08-06T22:17:17.357
@histocrat good point! I've edited my answer. – Cristian Lupascu – 2014-08-07T06:26:40.073
10
Use string interpolation!
To replace to_s. If you need parentheses around whatever you want to turn into a string, to_s is two bytes longer than string interpolation:
(n+10**i).to_s
"#{n+10**i}"
To replace concatenation. If you concatenate something surrounded by two other strings, interpolation can save you one byte:
"foo"+c+"bar"
"foo#{c}bar"
Also works if the middle thing is itself concatenated, if you just move the concatenation inside the interpolation (instead of using multiple interpolations):
"foo"+c+d+e+"bar"
"foo#{c+d+e}bar"
10
$_ is last read line.
print - if no argument given print content of $_~/regexp/ - short for $_=~/regexp/In Ruby 1.8, you have four methods in Kernel that operate on $_:
chopchompsubgsubIn Ruby 1.9, these four methods exist only if your script uses -n or -p.
If you want to print some variable often then use trace_var(:var_name){|a|p a}
1It seems that trace_var only works with global $variables – daniero – 2016-03-23T08:56:33.667
2
These are only available when you run Ruby with the -p or -n option. Reference.
10
length in if a.length<nlength is 6 bytes, a bit costly in code golf. in many situations, you can instead check if the array has anything at a given point. if you grab past the last index you will get nil, a falsey value.
So you can Change:
if a.length<5 to if !a[4] for -5 bytes
or
if a.length>5 to if a[5] for -6 bytes
or
if a.length<n to if !a[n-1] for -3 bytes
or
if a.length>n to if a[n] for -6 bytes
Note: will only work with an array of all truthy values. having nil or false within the array may cause problems.
4I always use size… But this is definitely better. BTW, works for String too. – manatwork – 2015-12-07T17:06:36.377
9
Build arrays using a=i,*a to get them in reverse order. You don't even need to initialize a, and if you do it doesn't have to be an array.
9
If you ever need to get a number from ARGV, get, or something similar to do something that many times, instead of calling to_i on it, you can just use ?1.upto x{do something x times} where x is a string.
So using ?1.upto(a){} instead of x.to_i.times{} will save you 2 characters.
You can also re-write things like p 1 while 1 or p 1 if 1 as p 1while 1 or p 1if 1
That example isn't very useful, but it could be used for other things.
Also, if you need to assign the first element of an array to a variable, a,=c will save two characters as opposed to a=c[0]
9
It's good to stay abreast of new language features that will help your golf game. There are a few great ones in the latest Rubies.
&.When you call a method that might return nil but you want to chain additional method calls if it's not, you waste bytes handling the nil case:
arr = ["zero", "one", "two"]
x = arr[5].size
# => NoMethodError: undefined method `size' for nil:NilClass
x = arr[5].size rescue 0
# => 0
The "safe navigation operator" stops the chain of method calls if one returns nil and returns nil for the whole expression:
x = arr[5]&.size || 0
# => 0
Array#dig & Hash#digDeep access to nested elements, with a nice short name:
o = { foo: [{ bar: ["baz", "qux"] }] }
o.dig(:foo, 0, :bar, 1) # => "qux"
Returns nil if it hits a dead end:
o.dig(:foo, 99, :bar, 1) # => nil
Enumerable#grep_vThe inverse of Enumerable#grep—returns all elements that don't match the given argument (compared with ===). Like grep, if a block is given its result is returned instead.
(1..10).grep_v 2..5 # => [1, 6, 7, 8, 9, 10]
(1..10).grep_v(2..5){|v|v*2} # => [2, 12, 14, 16, 18, 20]
Hash#to_procReturns a Proc that yields the value for the given key, which can be pretty handy:
h = { N: 0, E: 1, S: 2, W: 3 }
%i[N N E S E S W].map(&h)
# => [0, 0, 1, 2, 1, 2, 3]
Ruby 2.4 isn't out yet, but it will be soon and has some great little features. (When it's released I'll update this post with some links to the docs.) I learned about most of these in this great blog post.
Enumerable#sumNo more arr.reduce(:+). You can now just do arr.sum. It takes an optional initial value argument, which defaults to 0 for Numeric elements ([].sum == 0). For other types you'll need to provide an initial value. It also accepts a block that will be applied to each element before addition:
[[1, 10], [2, 20], [3, 30]].sum {|a,b| a + b }
# => 66
Integer#digitsThis returns an array of a number's digits in least-to-greatest significance order:
123.digits # => [3, 2, 1]
Compared to, say, 123.to_s.chars.map(&:to_i).reverse, this is pretty nice.
As a bonus, it takes an optional radix argument:
a = 0x7b.digits(16) # => [11, 7]
a.map{|d|"%x"%d} # => ["b", "7"]
Comparable#clampDoes what it says on the tin:
v = 15
v.clamp(10, 20) # => 15
v.clamp(0, 10) # => 10
v.clamp(20, 30) # => 20
Since it's in Comparable you can use it with any class that includes Comparable, e.g.:
?~.clamp(?A, ?Z) # => "Z"
String#unpack1A 2-byte savings over .unpack(...)[0]:
"".unpack(?U) # => [128123]
"".unpack(?U)[0] # => 128123
"".unpack1(?U) # => 128123
Numeric#ceil, floor, and truncateMath::E.ceil(1) # => 2.8
Math::E.floor(1) # => 2.7
(-Math::E).truncate(1) # => -2.7
This raises an error in earlier versions of Ruby, but is allowed in 2.4.
(a,b=1,2) ? "yes" : "no" # => "yes"
(a,b=nil) ? "yes" : "no" # => "no"
Golf Math::E.ceil(1) to Math::E.ceil 1, and likewise for floor and truncate. – Simply Beautiful Art – 2017-11-20T23:38:48.997
1@SimplyBeautifulArt I expect that someone golfing in Ruby will be able to make that leap themselves. – Jordan – 2017-11-20T23:50:49.810
For Enumerable#sum, .flatten.sum is 2 bytes shorter than .sum{|a,b|a+b} – Asone Tuhid – 2018-01-24T10:45:33.650
(-Math::E).truncate(1) is equivalent to -Math::E.truncate(1) which is 1 byte shorter – Asone Tuhid – 2018-03-01T12:21:24.767
1&. can be used with subscripting like this a&.[]i (1 byte shorter than a&.at i). Although, if brackets are required, a||a[i] is 1 byte is shorter than a&.[](i) or a&.at(i) – Asone Tuhid – 2018-03-01T12:24:27.560
7
Let's say you want to express a*(b+c). Because of precedence, a*b+c won't work (obviously). Ruby's cool way of having operators as methods comes to the rescue! You can use a.*b+c to make the precedence of * lower than that of +.
a*(b+c) # too long
a*b+c # wrong
a.*b+c # 1 byte saved!
This can also work with the ! and ~ operators (things like unary + or unary - don't work because their methods are -@ and +@, saving () but adding .@)
(~x).to_s # too long
~x.to_s # error
x.~.to_s # 1 byte saved!
7
Scientific notation can often be used to shave off a char or two:
x=1000
#versus
x=1e3
9Note: This will return a Float value (1000.0) instead of an Integer, which may cause inaccurate results with large numbers. – Wile E. Coyote – 2011-02-25T11:02:40.177
4Ah, nice 1e2 is better than 100.0 when a percentage is needed. – Phrogz – 2011-02-26T06:36:55.447
Similar to this principle, 1.0* is 1 char shorter than .to_f – Unihedron – 2017-12-16T13:44:38.340
7
a.uniq # before
a|[] # after
^^
If you will be using an empty array [] in a variable, you can save even more bytes:
a.uniq;b=[] # before
a|b=[] # after
^^^^^
2For the first case, a&a is 1 byte shorter – Asone Tuhid – 2018-03-07T12:59:59.760
6
I just attempted a TDD code-golf challenge i.e. Write shortest code to make specs pass. The specs were something like
describe PigLatin do
describe '.translate' do
it 'translates "cat" to "atcay"' do
expect(PigLatin.translate('cat')).to eq('atcay')
end
# And similar examples for .translate
end
end
For the sake of code-golf, one need not create a module or class.
Instead of
module PigLatin def self.translate s;'some code'end;end
one can do
def(PigLatin=p).translate s;'some code'end
Saves 13 characters!
@histocrat: Now I get it. It's because translate has been defined on nil. – Eric Duminil – 2017-03-20T13:48:54.503
7Ha, very thorough. Not only did you add the necessary behavior to PigLatin, but also to @pig_latin, $pig_latin, and 'pig'['latin']. – histocrat – 2014-02-27T15:23:19.620
6
Don't use #each. You can loop over all elements just fine with #map. So instead of
ARGV.each{|x|puts x}
you can do the same in less bytes.
ARGV.map{|x|puts x}
Of course, in this case puts $* would be even shorter.
There are literals for rational and complex numbers:
puts 3/11r == Rational(3,11)
puts 3.3r == Rational(66,20)
puts 1-1.i == Complex(1,-1)
=> true
true
true
You can use most bytes within strings. "\x01" (6 bytes) can be shortened to "" (3 bytes). If you only need this one byte, this can be shortened even further to ? (2 bytes).
By the same token, you can get newlines shorter like this:
(0..10).to_a.join'
'
=> "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10"
You can use ?\n and ?\t as well, which is one byte shorter than "\n" and "\t". For obfuscation, there also ?\s, a space.
Use constants instead of passing arguments around, even if you need to change them. The interpreter will give warnings to stderr, but who cares. If you need to define more variables related to each other, you can chain them like this:
A=C+B=7+C=9
=> A=17, B=16, C=9
This is shorter than C=9;B=16;A=17 or C=0;B=C+7;A=C+B.
If you need an infinite loop, use loop{...}. Loops of unknown length may be shorter with other loops:
loop{break if'
'==f(gets)}
while'
'!=f(gets);end
Some more gsub/regexp tricks. Use the special '\1' escape characters instead of a block:
"golf=great short=awesome".gsub(/(\w+)=(\w+)/,'(\1~>\2)')
"golf=great short=awesome".gsub(/(\w+)=(\w+)/){"(#{$1}~>#{$2})")
And the special variables $1 etc. if you need to perform operations. Keep in mind they are defined not only inside the block:
"A code-golf challenge." =~ /(\w+)-(\w+)/
p [$1,$2,$`,$']
=> ["code", "golf", "A ", " challenge."]
Get rid of spaces, newlines, and parentheses. You can omit quite a bit in ruby. If in doubt, always try if it works without, and keep in mind this might break some editor syntax highlighting...
x+=1if$*<<A==????::??==??
"Please post one tip per answer." Also ?\n is nice, but not really shorter than actually putting a newline character inside quotes. (same for tab) – Martin Ender – 2015-05-07T23:29:28.203
And puts$* is even shorter. – Cyoce – 2017-11-07T05:20:01.070
I know you were trying to prove a point but I'm pretty sure that last example is the same as x+=1;$*<<A – Asone Tuhid – 2018-03-01T14:03:37.240
6
Yet another way to use the splat operator: if you want to assign a single array literal, a * on the left-hand side is shorter than brackets on the right-hand side:
a=[0]
*a=0
With multiple values you don't even need the splat operator (thanks to histocrat for correcting me on that):
a=[1,2]
a=1,2
The latter case doesn't actually need the splat. – histocrat – 2015-08-15T22:53:07.067
@histocrat Oh wow, I thought the second value would just be discarded in that case. – Martin Ender – 2015-08-15T22:53:45.603
1I can't believe I haven't known these in all the time I've spent golfing in Ruby. – Doorknob – 2016-01-02T03:07:22.543
6
When a challenge requires that you output multiple lines, you don't have to loop through your results in order to print each line of e.g. an array. The puts method will flatten an array and print each element on a separate line.
> a = %w(testing one two three)
> puts a
testing
one
two
three
Combining the splat operator with #p you can make it even shorter:
p *a
The splat operator (technically the *@ method, I think) also casts your non-array enumerables to arrays:
> p a.lazy.map{|x|x*2}
#<Enumerator::Lazy: #<Enumerator::Lazy: [1, 2, 3]>:map>
vs
> p *a.lazy.map{|x|x*2}
2
4
6
1*@ is not a method, splat is syntactic sugar – Asone Tuhid – 2018-01-24T10:55:14.920
6
Use || instead or and && instead and.
Beside the one character from and you can save the spaces
(and perhaps the bracket) around the operator.
p true and false ? 'yes' :'no' #-> true (wrong result)
p (true and false) ? 'yes' :'no' #-> 'no'
p true&&false ? 'yes' :'no' #-> 'no', saved 5 characters
p true or false ? 'yes' :'no' #-> true (wrong result)
p (true or false) ? 'yes' :'no' #-> 'yes'
p true||false ? 'yes' :'no' #-> 'yes', saved 4 characters
If you loop on an array you normally use each. But map loops also over an array and it is one character shorter.
6
Kernel#p is a fun method.
Use p var instead of puts var. This works perfectly with integers and floats, but not with all types. It prints quotation marks around strings, which is probably not what you want.
Used with a single argument, p returns the argument after printing it.
Used with multiple arguments, p returns the arguments in an array.
Use p (with no arguments) instead of nil.
10Unfortunately p 'some string' prints "some string" and not just some string which is often criticised by others. – Patrick Oscity – 2013-06-01T21:11:12.817
1Basically p s is the same as puts s.inspect, but it returns s – Cyoce – 2016-11-03T23:37:59.877
5
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
5
To join an array, instead of this
[...].join
do this
[...]*''
which saves 2 bytes. To join with a separator use
[...]*?,
5
Use Goruby instead of Ruby, which is something like an abbreviated version of Ruby. You can install it with rvm via
rvm install goruby
Goruby allows you to write most of your code as you would be writing Ruby, but has additional abbreviations built in. To find out the shortest available abbreviation for something, you can use the helper method shortest_abbreviation, for example:
shortest_abbreviation :puts
#=> "pts"
Array.new.shortest_abbreviation :map
#=> "m"
String.new.shortest_abbreviation :capitalize
#=> "cp"
Array.new.shortest_abbreviation :join
#=> "j"
Also very handy is the alias say for puts which itself can be abbreviated with s. So instead of
puts [*?a..?z].map(&:capitalize).join
you can now write
s [*?a..?z].m(&:cp).j
to print the alphabet in capitals (which is not avery good example). This blog post explains more stuff and some of the inner workings if you are interested in further reading.
PS: don't miss out on the h method ;-)
More than 2 years later and I finally figured out what this answer reminds me of...
– undergroundmonorail – 2015-05-22T13:53:19.2704
while...endIf you need to break out of the loop, while condition;code;end will probably be shorter than loop{code;condition||break}.
The ; before end is not always required, eg. while condition;p("text")end
until c;...;end is equivalent to while !c;...;end and 1 byte shorter.
Note that in most cases code while condition and code until condition are significantly shorter as they don't require the end keyword and can often drop semicolons. Also, i+=1 while true is equivalent to i+=1while true and 1 byte shorter.
redoWhen run, the redo command jumps back to the beginning of the block it's in.
When using redo in a lambda, you will have to move any setup variables to the arguments to avoid them being reset at every iteration (see examples).
Recursion can be shorter is some cases. For instance, if you're working on an array element by element, something like f=->s,*t{p s;t[0]&&f[*t]} can be shorter than the alternatives depending on the stuff.
Note that per the current consensus, if you're calling your function by name, you need to include the assignment (f=) in the byte count making all recursive lambdas 2 bytes longer by default.
evalIf you need to run some code n times, you can use eval"code;"*n.
This will concatenate code; n times and run the whole thing.
Note that in most cases you need to include a ; after your code.
1 to a inclusive:->n{i=0;loop{p i+=1;i<n||break}} # 32 bytes
f=->n,i=1{i>n||p(i)&&f[n,i+1]} # 30 bytes
->n,i=0{p(i+=1)<n&&redo} # 24 bytes
->n{i=0;p i+=1while i<n} # 24 bytes
->n{i=0;eval"p i+=1;"*n} # 24 bytes
->n{n.times{|i|p i+1}} # 22 bytes # thanks to @benj2240
In this case, since the end-point is defined (n), the n.times loop is the shortest.
The redo loop works because i+=1 modifies i and returns its new value and p(x) returns x (this is not true of print and puts).
g and a number n, find the first number strictly larger than n for which g[n] is truthy->g,n{(n+1..1/0.0).find{|i|g[i]}} # 33 bytes
->g,n{loop{g[n+=1]&&break};n} # 29 bytes
f=->g,n{n+=1;g[n]?n:f[g,n]} # 27 bytes
->g,n{1until g[n+=1];n} # 23 bytes
->g,n{g[n+=1]?n:redo} # 21 bytes
In this case, with an unknown end-point, redo is the best option.
The (n+1..Inf) loop is equivalent to simply looping indefinitely but more verbose.
A 1 (or anything else) is required before the until keyword to complete the syntax, using a number allows you to drop a space.
The eval method is not viable in this case because there is neither a defined end-point nor an upper bound.
1.times can often be even shorter for fixed loops, eg ->n{n.times{|i|p i+1}} for 22 bytes – benj2240 – 2018-03-16T15:07:37.580
4
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
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
.:.: is syntactic sugar for the .method method, e.g.:
(1..5).map(&1r.:/)
# => [(1/1), (1/2), (1/3), (1/4), (1/5)]
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!
..3Analogous 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 elementsThis 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).
4
You may be able to save 2 chars and use
[*(...)]
instead of
(...).to_a
For example, suppose we have a range that we want as an array:
(1..2000).to_a
Just do it like this:
[*1..2000] # Parentheses around the (ran..ge) is not needed!
And now you have your range as an array.
5I think [*1..2000] works, too? – Lynn – 2015-08-24T18:38:36.657
4
a.push x
can be shortened to:
a<<x
for -4 bytes.
3Note: this also works for Strings – Cyoce – 2016-11-04T01:13:41.047
4
Array#assoc/rassocWhen 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"]]
a.any?{|*,x|x=="bad"} # => false
a.rassoc("bad") # => nil
For the a.any? line in the rassoc example, what does |x,| do? How is it different from |x|? – Cyoce – 2016-11-04T01:05:21.173
@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 – 2016-11-04T01:27:27.930
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 – 2016-11-04T01:39:59.027
4
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.
3
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 – 2018-03-01T12:13:33.520
3
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.
(See also New features in Ruby 2.3 and 2.4.)
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
(?~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 HashI 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}
All of the changes in Ruby 2.6: https://rubyreferences.github.io/rubychanges/2.6.html
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 blockSaves 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.
>> 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 RangeAn alias for Range#step:
((1..10) % 2).to_a
# => [1, 3, 5, 7, 9]
Random.bytesCould be handy.
Random.bytes(10)
# => "'\xB2\xD7\ny"
3
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.
4Or you can just add -rbenchmark -rprime to the character/byte count. That's usual in choice golf. – nyuszika7h – 2014-07-05T12:21:15.577
3
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)
3
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).
3like wise, (i+1) can become -~i – Cyoce – 2016-11-04T01:16:19.073
3
This is a bit situational, but every byte counts!
puts"thing" # before
puts:thing # after
^
2
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
2
eval instead of reduceWhile 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*?*)
^^^^^^^^^^^^^^
2eval a*?* to save another char. – Unihedron – 2018-01-29T06:31:48.113
also for case 2, using .tr' ',?* is way more concise than .split*?*... – Unihedron – 2018-01-29T06:33:07.937
1also, note that a.reduce:* is valid if brackets aren't required though I think it can always be replaced with eval a*?* – Asone Tuhid – 2018-03-01T12:10:08.103
2
When working with arrays, .compact can be replaced with -[nil] to save 2 chars.
2-[p] saves another 2. – Doorknob – 2018-08-25T16:12:45.610
1
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.
1
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.
1
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)
1
~// 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.
!/regex/ equivalent to $_!~/regex/ returning true or false.
!// 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.
1
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 [.
4Or use the triple equals thing: Array===a ;) – daniero – 2015-06-26T23:33:21.683
6How about a==[*a]? – histocrat – 2016-11-04T01:23:28.107
0
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.
0
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
0
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.
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 – 2017-08-30T12:28:57.550