1

I have this code snippet, a bucket in this case is just an array within a larger array:

def Dict.get_slot(aDict, key, default=nil)
    # Returns the index, key, and value of a slot found in a bucket.
    bucket = Dict.get_bucket(aDict, key)

    bucket.each_with_index do |kv, i|
        k, v = kv
        if key == k
            return i, k, v
        end
    end

    return -1, key, default
end

The two variables called k and v are set to the contens of kv. But how can this work, when kv only contains one value at a time?

I wrote this into another file:

    bucket = ['key', 'value']
    key = 'key'
    bucket.each_with_index do |kv, i|
        k, v = kv
        if key == k
        puts k, v, i
        end
    end

And then the v variable was empty:

key

0

My question is, why does multiple assignment work in the first example, but not in the second?

2 Answers 2

6

bucket is a dictionary, simply put: a list of pairs of values, not just a list of values. Consider:

bucket.each do |kv|
  # kv is an array: [some_k, some_v]
  k, v = kv
  # k is some_k
  # v is some_v
end

bucket.each_with_index do |kv, i|
  # kv is again an array: [some_k, some_v]
  k, v = kv
  # k is some_k
  # v is some_v
end

As a side note, this kind of "pattern matching" can also be used in nested form for the block parameters directly:

bucket.each_with_index do |(k, v), i|
  # k is some_k
  # v is some_v
end
Sign up to request clarification or add additional context in comments.

2 Comments

This is from "Learn Ruby the Hard Way" exercise 39. so basically kv is shortcut for (k,v)?
kv will contain a two element array with the key and the value. To extract the key and the value into variables the extra step k, v = kv is needed. If you write (k,v) the array is directly destructured and the key and value will be assigned to k and v respectively. The extra step is not necessary in this case.
1

When you're calling bucket.each_with_index it first acts on 'key', then 'value'

You could try nested arrays, so in this example each member of the array is an array with two items.

irb(main):012:0> [['a','b'],['c','d']].each_with_index{|x,i|puts "#{i}: #{x}"}
0: ["a", "b"]
1: ["c", "d"]

You can then identify these by index

irb(main):019:0> [['a','b'],['c','d']].each_with_index{|x,i|puts "#{i}: #{x[0]} - #{x[1]}"}
0: a - b
1: c - d

Or set these as values with the syntax you used:

irb(main):020:0> [['a','b'],['c','d']].each_with_index{|x,i| a,b = x ; puts "#{i}: #{a} -  #{b}"}
0: a - b
1: c - d

Without the one liners:

bucket = [
  ['a','b'],
  ['c','d']
]
bucket.each_with_index do |x, index|
  k, v = x
  puts index
  puts "#{k} = #{v}"
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.