A community-curated list of one-liners (or several-liners if elegance demands) in Ruby
File.open(filename, 'rb') { |file| file.read }Dir.homeThis 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)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(str1 + str1)[str2] == str2My 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]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.
[*1..n].product([*1..n]).map { |arr| arr.reduce(:*) }.each_slice(n).to_aOr, 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) } }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_hYou can use parallel assignment in conjunction with the splat operator if you're planning on using the head:
head, *rest = aBut 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.
a.group_by(&:itself).select { |_, v| v.size > 1 }.keysYou can replace group_by(&:itself) with group_by { |n| n } for lesser versions of Ruby.
a.each_cons(n).map { |interval| interval.reduce(:+) / n.to_f }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.
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.
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)]- The straightforward way:
k, v = h.keys, h.values- Or more cryptically for impressing your nerdy friends:
k, v = *h.to_a.transposeActiveSupport 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) }.firstThis 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)(1..n).reduce(1, :*) if n.is_a?(Integer) && n > -1Given 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)
endNote that this implementation has one major drawback — it mutates its argument.
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
endThis 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', '*'))