Last active
August 29, 2015 13:57
-
-
Save zobar/9607820 to your computer and use it in GitHub Desktop.
Look and say, ruby & clojure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns look-and-say) | |
(defn- consecutive [string] | |
(map first (re-seq #"(.)\1*" string))) | |
(defn- say [chars] | |
[(count chars) (first chars)]) | |
(defn- get-next [string] | |
(apply str (mapcat say (consecutive string)))) | |
(defn look-and-say [string] | |
(iterate get-next string)) | |
; (def las (look-and-say/look-and-say "1")) | |
; (take 2 las) | |
; => ("1" "11") | |
; (take 2 las) | |
; => ("1" "11") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module LookAndSay | |
class << self | |
def look_and_say(string) | |
Enumerator.new do |yielder| | |
current = string | |
loop do | |
yielder << current | |
current = get_next current | |
end | |
end | |
end | |
private | |
def consecutive(string) | |
string.scan(/((.)\2*)/).map &:first | |
end | |
def say(chars) | |
[chars.length, chars[0]] | |
end | |
def get_next(string) | |
consecutive(string).map(&method(:say)).join '' | |
end | |
end | |
end | |
# las = LookAndSay.look_and_say '1' | |
# las.take 2 | |
# => ["1", "11"] | |
# las.take 2 | |
# => ["1", "11"] |
Ah... heh. Well, for my solution, yeah, #take doesn't work perfectly. There's a slightly longer way to write it where it works correctly, but harder to fit into a tweet:
def iterate(meth, arg)
Enumerator.new do |yielder|
current = arg
loop do
yielder << current
current = send(meth, current)
end
end
end
By reassigning the method parameter, it prevents #take from working correctly.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Honestly, it depends on what you’re trying to do. When you call #each with a block, it consumes the entire collection, so it’s not good if the collection is infinite, or if you want more control over when successive elements are generated.
But if you want to be most in line with StdLib, then do both: if a block is passed in to your #each, explicitly yield to that block for every element. If no block is passed in, then return an enumerator, and the caller can decide how to handle it. But… I think most of the time people don’t do that, ‘cause they don’t need to.