Skip to content

Instantly share code, notes, and snippets.

@dfurber
Last active November 24, 2017 21:39
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dfurber/7547568 to your computer and use it in GitHub Desktop.
Save dfurber/7547568 to your computer and use it in GitHub Desktop.
Experiments in tail recursion with Ruby, implementing group_by, index_by, in_groups_of, and sort_by without iteration or conditionals. Because why not?
items = %w{foo bar baz goo gar gaz hoo har haz}
def recurse_array(ary, &block)
head, *tail = ary
head and block.call(head)
tail.any? and recurse_array(tail, &block)
end
puts "First the items in order:\n"
recurse_array items do |item|
puts item
end
puts "\n"
puts "And now in reverse order: \n"
recurse_array items.reverse do |item|
puts item
end
puts "\n"
puts "Now let's group them by the first letter: \n"
grouped = {}
recurse_array(items) do |item|
(grouped[item[0]] ||= []) << item
end
puts grouped.inspect
def sort_by(list, &block)
sl = list.clone
sl.size <=1 and sl or begin
pivot = sl.pop
left, right = sl.partition { |e| block.call(e) < block.call(pivot) }
sort_by(left, &block) + [pivot] + sort_by(right, &block)
end
end
def tuple_array_to_hash(ary)
new_hash = {}
recurse_array(ary) { |item| new_hash[item[0]] = item[1] }
new_hash
end
def ksort(grouped, &block)
tuple_array_to_hash sort_by(grouped.to_a, &:first)
end
def group_by(ary, &block)
grouped, sorted = {}, {}
recurse_array(ary) do |item|
(grouped[block.call(item)] ||= []) << item
end
ksort grouped
end
puts "\n"
puts "Now let's group them and key sort them:\n"
grouped_items = group_by(items) { |item| item[0] }
puts grouped_items.inspect
def index_by(ary, &block)
keyed = {}
recurse_array(ary) { |item| keyed[block.call(item)] = item }
keyed
end
puts "\n"
puts "Now let's index them by the MD5 hash of each item:\n"
require 'digest/md5'
indexed_items = ksort index_by(items) { |item| Digest::MD5.hexdigest item }
puts indexed_items.inspect
def head_and_tail(ary, size)
return ary.take(size), ary.drop(size)
end
def in_groups_of(ary, size, &block)
head, tail = head_and_tail ary, size
head and block.call(head)
tail.any? and in_groups_of(tail, size, &block)
end
puts "\n"
puts "Now in groups of 3:\n"
in_groups_of(items, 3) { |group| puts group.inspect }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment