My favorite little-known fact about Ruby hashes is that they respond to `to_proc` and can be used as procs. For example, you can do this:
a = { 1 => 'a', 2 => 'b' }
[1, 2, 3].map(&a)
#=> ['a', 'b', nil]
a = { 1 => 'a', 2 => 'b' }
[1, 2, 3].map(&a)
#=> ['a', 'b', nil]
fib = Hash.new do |k, v|
next 1 if v == 0 || v == 1
k[v-1] + k[v-2]
endfib = Hash.new {|hash, key| hash[key] = key < 2 ? key : hash[key-1] + hash[key-2] }
Example: fib[123] # => 22698374052006863956975682
Makes use of memoization.
fib = Hash.new do |k, v|
next 1 if v == 0 || v == 1
k[v] = k[v-1] + k[v-2]
end
I like yours better though, it seems a lot simpler with the less than 2 check. A = Hash.new { |a,(m,n)| a[[m,n]] = m==0 ? n+1 : n==0 ? a[[m-1,1]] : a[[m-1, a[[m, n-1]]]] }
A[[3,4]] #=> 125
A.inspect #=> ... long
However, the application utility of a self-populating lazily-evaluated lookup structure goes further. A hash with a default function works great as a simple caching wrapper for all manner of results, for example when talking to slow or fine-grained APIs. fib = Hash.new do |k, v|
next 1 if v == 0 || v == 1
unless k.key? v
k[v] = k[v-1] + k[v-2]
end
k[v]
endk[v] ||= k[v-1] + k[v-2]
k[v] || (k[v] = k[v-1] + k[v-2])
And that first k[v] (unlike k.key?(v)) will trigger the Hash.new block again, so it'll recurse until it runs out of stack. But neither check is necessary, because the Hash.new block will only ever get called if k.key?(v) is false.If you want a more compact version, you could do:
fib = Hash.new do |k,v|
next 1 if v == 0 || v == 1
k[v] = k[v-1] + k[v-2]
end (def fib (lazy-cat [0 1] (map + fib (rest fib))))
=> (take 10 fib)
(0 1 1 2 3 5 8 13 21 34)
Explanation:
0 1 1 2 3 5 ; this is fib
+ 1 1 2 3 5 8 ; this is (rest fib)
---------------
1 2 3 5 8 13 ; this is (map + fib (rest fib))
; and the sequence needs to be initialized with (lazy-cat [0 1] ...But now I'm wondering where that would be a better solution than just using the `Hash#values_at` method...?