-1

Trying to understand the following code which returns the F(n) for the sequence number in the method call. It is actually from an older SO post. I do understand the Fibonacci numbers.

fib = Hash.new{ |h,k| h[k] = k < 2 ? k : h[k-1] + h[k-2]}
fib[6]  # => 8

I know it's a Hash, and understand all the syntax. My stumbling block is the operation at the end of the line - h[k-1] + h[k-2]

Perhaps I do not fully understand the recursion method. Thanks for the help! .

stuartambient
  • 127
  • 1
  • 1
  • 10
  • The ternary is the value that goes into h[k]. If k < 2, then k goes into h[k]. Otherwise, it's h[k-1] + h[k-2]. For 6, it would be h[5] + h[4]. – msergeant Aug 01 '17 at 18:34
  • Ok, but 6 returns 8 (8 being the 6th fibonacci number), so how is the h[k-1] + h[k-2] getting the fibonacci sequence. 5 + 4 is not 8, so I'm still confused. – stuartambient Aug 01 '17 at 18:41
  • h is a hash. When you call fib[6], it does some recursive calls to the hash and ends up looking like this: {1=>1, 0=>0, 2=>1, 3=>2, 4=>3, 5=>5, 6=>8}. h[5] == 5 and h[4] == 3. 5 + 3 == 8 – msergeant Aug 02 '17 at 00:07

1 Answers1

3

That code is the same as the following:

fib = Hash.new do |h,k|
  if k < 2
    h[k] = k
  else 
    h[k] = h[k-1] + h[k-2]
  end
end

When you access a key that is not part of the hash fib it will default to whatever is in the block, where h is the hash itself and k is the key you want to access.

Using fib[6] the evaluation of if k < 2 returns false, so the else clause is executed:

h[k] = h[k-1] + h[k-2]
h[6] = h[6-1] + h[6-2]
h[6] = h[5] + h[4]

As you can see both h[5] and h[4] also try to access a non-existing key, so the same evaluation is made for both, and both return false from the condition in if, so:

h[5] = h[5-1] + h[5-2]
h[5] = h[4] + h[3]

h[4] = h[4-1] + h[4-2]
h[4] = h[3] + h[2]

Again, both h[3] and h[2] look for a non-existing key, so the process repeats:

h[3] = h[3-1] + h[3-2]
h[3] = h[2] + h[1]

h[2] = h[2-1] + h[2-2]
h[2] = h[1] + h[0]

Finally, the same goes with h[1] and h[0], but this time the condition in if will evaluate to true, so now it will return h[k] = k:

h[0] = 0
h[1] = 1

Now, after going all the way down, we go back up:

h[2] = h[1] + h[0]
h[2] = 1 + 0
h[2] = 1

h[3] = h[2] + h[1]
h[3] = 1 + 1
h[3] = 2

h[4] = h[3] + h[2]
h[4] = 2 + 1
h[4] = 3

h[5] = h[4] + h[3]
h[5] = 3 + 2
h[5] = 5

h[6] = h[5] + h[4]
h[6] = 5 + 3
h[6] = 8

So:

fib[6]
#=> 8
Gerry
  • 10,337
  • 3
  • 31
  • 40
  • I followed along till going back up, `h[3]`. Why did` h[2] + h[1]` add as `1 + 1`. Same with the rest, like the next - `h[4] = h[3] + h[2] is added 2 + 1`. – stuartambient Aug 01 '17 at 20:31
  • @stuartambient This is just recursion, to understand it better try solving first `fib[0]`, then `fib[1]` and so on. For example: `fib[0]` will return `0`, thus, whenever `h[0]` is executed in the code (in the above example) its value will be `0`; the same with `fib[1]`. Now that you now the values for `h[0]` and `h[1]` try to figure out `fib[2]` using the logic displayed above. – Gerry Aug 01 '17 at 21:40
  • Thank you! I will try that again using the information you've given me. I'm not well versed in recursion and just recently did a fibonacci method without recursion. This would be the next step and hopefully at some point I'll get it. Thanks for the help! – stuartambient Aug 01 '17 at 21:45
  • @stuartambient `h[2]` is the same than `fib[2]`; that means that `k` value is `2`. Step 1: `if k < 2` becomes `2 < 2`, that is: **false**, so `else` code is execued; Step 2: `h[k] = h[k-1] + h[k-2]`, which becomes `h[2] = h[2-1] + h[2-2]`, which becomes `h[2] = h[1] + h[0]`. But now you know the values for `h[0]` and `h[1]`, right? `h[2] = 1 + 0`. Now you see why `fib[2] == 1`? Now go for `f[3]` up to `f[6]`. – Gerry Aug 01 '17 at 21:49
  • I'm still sort of stuck at this point, going up. I don't understand where the `1+1` came from in the sequence. In other words where did `h[k-2]` go. `h[3] = h[2] + h[1]` `h[3] = 1 + 1` h[3] = 2` Obviously I know nothing about, nor have ever used recursion before. This is probably the biggest hurdle for me in understanding it. – stuartambient Aug 01 '17 at 23:55
  • @stuartambient Check [here](https://stackoverflow.com/questions/25676961/understanding-how-recursive-functions-work), [here](https://stackoverflow.com/questions/6418017/what-is-recursion-and-how-does-it-work) and [here](https://stackoverflow.com/questions/717725/understanding-recursion) for some explanations about recursion. When you get a better grasp at it come back to this answer. – Gerry Aug 02 '17 at 12:22
  • @stuartambient Also, do you understand how `Hash.new` with a _block_ works? – Gerry Aug 02 '17 at 12:23
  • I'm looking over the links, thank you!. As far as understanding how Hash.new works with blocks, I've used them a few times now. Used for counting items in a list for instance, The other thing I did with this particular code is to take off the conditionals and I see that just sending a number to 'h[k] = k' will give me a key/value of the number. Both key and value get the same number. So I'd say there is some kind of dynamic behavior that goes on between the hash and block, particularly in these cases. – stuartambient Aug 02 '17 at 16:04