Skip to content
A community-curated list of one-liners in Ruby
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
README.md

README.md

Facets

A community-curated list of one-liners (or several-liners if elegance demands) in Ruby

Files, Folders, and Paths

Convert the contents of filename to a string
File.open(filename, 'rb') { |file| file.read }
Get the current user's home directory
Dir.home

This only works if ENV['HOME'] is set, though. RubyTapas #10 gives us an alternative using Etc to find the current user's login name and passing that to Dir.home:

Dir.home(Etc.getlogin)

Strings

Calculate the Hamming distance between two strings str1 and str2 (returns nil if str1 and str2 are of unequal length):
str1.chars.zip(str2.chars).reduce(0) { |sum, (x, y)| sum + (x == y ? 0 : 1) } if str1.size == str2.size
Determine whether one string str1 is a rotation of another string str2:
(str1 + str1)[str2] == str2
Get the nth bit of an Integer j:

My first inclination would be to convert to binary and use [], i.e., j.to_s(2)[n].to_i, but you can call [] directly on an Integer:

j[n]

Arrays

Remove all instances of value l from an array a and return the result
a - [l]

Or a -= [l] if you would like to reasign the result to a. This is the most elegant way I've seen of doing this. Doing something like a.delete(l) returns l rather than the updated value of a which disrupts method chaining. You could always do a.tap { |x| x.delete(l) }, but I think the above line is superior and just as chainable if enclosed in parentheses.

Convert an array a with even index whose elements are alternating key value pairs (e.g., [k1, v1, k2, v2,..., kn, vn] into the respective hash h
h = Hash[*a]

This is likely not a good idea if a happens to be a large dataset as the splat operator will expand all contents of the array to the stack. In that case, you can use h = Hash[a.each_slice(2).to_a].

In the event a is already a 2D array of the form [[k1, v1], [k2, v2],..., [kn, vn]], you can simply do h = Hash[a]. And from Ruby 2.1 onwards, you can simply use Array#to_h: h = a.to_h.

Create an nxn multiplication table represented by a 2-dimensional array:
[*1..n].product([*1..n]).map { |arr| arr.reduce(:*) }.each_slice(n).to_a

Or, if you're using ActiveSupport:

[*1..n].product([*1..n]).map { |arr| arr.reduce(:*) }.in_groups(n)

And in terms of clarity, this one's about as good as it gets:

Array.new(n) { |x| Array.new(n) { |y| (x+1)*(y+1) } }
Calculate the frequency distribution of an array a:

There are many ways to do this, but using Enumerable#each_with_object seems to be the most idiomatic:

a.each_with_object(Hash.new(0)) { |element, frequency| frequency[element] += 1 }

Enumerable#reduce also works, but feels clumsier. Notice that the block parameters are reversed compared to the above and the need to explicitly return the accumulator on each pass:

a.reduce(Hash.new(0)) { |frequency, element| frequency[element] += 1; frequency }

And yet another way using Ruby 2.2+ that seems truest to a functional style:

a.group_by(&:itself).map { |k, v| [k, v.size] }.to_h
Get all but the first element of an array a:

You can use parallel assignment in conjunction with the splat operator if you're planning on using the head:

head, *rest = a

But if you just want the rest, using drop is better:

a.drop(1)

Both are preferable to a[1..-1] in that they return [] rather than nil if a is empty.

Find all duplicate values in an array a (Ruby 2.2+):
a.group_by(&:itself).select { |_, v| v.size > 1 }.keys

You can replace group_by(&:itself) with group_by { |n| n } for lesser versions of Ruby.

Calculate rolling averages of an array a over interval length n:
a.each_cons(n).map { |interval| interval.reduce(:+) / n.to_f }
Reduce an array a of Boolean values

For and, or, and xor, we can use Enumerable#reduce paired with the appropriate logical operator, i.e., a.reduce(:&), a.reduce(:|), and a.reduce(:^), respectively.

For reducing over and and or, I find a.all? and a.any? to be more idiomatic than explicit use of reduce.

"Map compact" or "select map"

This one is best illustrated by an example. Note, I don't think there is a particularly elegant way to do what I'm about to describe in Ruby. A common idiom is to map over a collection and select the resulting values for those elements which conform to some predicate.

For example, suppose we have an array a = [1, 2, 3, 4, 5] and want to get a resulting collection that adds 1 to each element only if that element is even. We can achieve this in several ways:

a = [1, 2, 3, 4, 5]

a.map { |l| l + 1 if l.even? }.compact                      # => [3, 5]
a.select(&:even?).map { |l| l + 1 }                         # => [3, 5]
a.each_with_object([]) { |l, res| res << l + 1 if l.even? } # => [3, 5]
a.reduce([]) { |res, l| res.push(l + 1) if l.even?; res }   # => [3, 5]

All of these one-liners return the desired result, all of them feel clumsy.

Hashes

Create a hash h from two arrays k and v of equal length that represent h's keys and values, respectively:
h = Hash[k.zip(v)]
Decompose a hash h into two arrays k and v that respresent h's keys and values, respectively:
  1. The straightforward way:
k, v = h.keys, h.values
  1. Or more cryptically for impressing your nerdy friends:
k, v = *h.to_a.transpose
Remove key-value pairs in hash h given keys in array a:

ActiveSupport has a nifty little method for this called Hash#except. The best I could come up with for doing this in one line with Ruby non-destructively is

hash.tap { |h| a.map { |k| h.delete(k) } }
Weighted random sampling without replacement of a hash h's keys whose values are weighted probabilities that sum to 1:
h.max_by { |_, weight| rand ** (1.0/weight) }.first

This is essentially the weighted analogue of Array#sample. With Ruby 2.2+, we also have the analogue of Array#sample(n):

h.max_by(n) { |_, weight| rand ** (1.0/weight) }.map(&:first)

Regular Expressions

Calculations

Compute n! for all nonnegative integers n (returns nil otherwise):
(1..n).reduce(1, :*) if n.is_a?(Integer) && n > -1

Miscellaneous

Given an mxn matrix, return an array that represents the clockwise spiral path from the top left to the center. For example, given
matrix = [[1,2,3],
          [8,9,4],
          [7,6,5]]

spiral(matrix) should return [1, 2, 3, 4, 5, 6, 7, 8, 9]

def spiral(matrix)
  matrix.empty? ? [] : matrix.shift + spiral(matrix.transpose.reverse)
end

Note that this implementation has one major drawback — it mutates its argument.

Symbol#to_proc with arguments

This isn't a one-liner nor is it something I recommend without extreme caution as it patches a core class, but it is one of the slickest — if not the slickest — Ruby hacks I've ever seen.

Open up the Symbol class and add a call method to it that contains the following lambda:

class Symbol
  def call(*args, &block)
    ->(caller, *rest) { caller.send(self, *rest, *args, &block) }
  end
end

This gives Symbol#to_proc the superpower of accepting arguments. so, instead of doing, e.g.,

nums = [1, 2, 3, 4]
text = %w(this is a test)

nums.map { |num| num ** 1i }
text.map { |word| word.gsub('s', '*') }

we can do

nums.map(&:**.call(1i))
text.map(&:gsub.call('s', '*'))

But there's one more trick here. By naming our method call, we can use the shorter .() syntax:

nums.map(&:**.(1i))
text.map(&:gsub.('s', '*'))
You can’t perform that action at this time.