Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I pass a lambda to Hash.each?

Tags:

ruby

lambda

How can I pass a lambda to hash.each, so I can re-use some code?

> h = { a: 'b' }
> h.each do |key, value| end
 => {:a=>"b"}
> test = lambda do |key, value| puts "#{key} = #{value}" end 
> test.call('a','b')
a = b
> h.each &test
ArgumentError: wrong number of arguments (1 for 2)
  from (irb):1:in `block in irb_binding'
  from (irb):5:in `each'
  from (irb):5
  from /Users/jstillwell/.rvm/rubies/ruby-1.9.3-p362/bin/irb:16:in `<main>'
> h.each test
ArgumentError: wrong number of arguments(1 for 0)
  from (irb):8:in `each'
  from (irb):8
  from /Users/jstillwell/.rvm/rubies/ruby-1.9.3-p362/bin/irb:16:in `<main>'
like image 332
DragonFax Avatar asked Feb 21 '13 00:02

DragonFax


2 Answers

each yields the current element to the block, ergo the lambda needs to take one argument, not two. In case of a Hash the element being yielded is a two-element Array with the first element being the key and the second element being the value.

test = lambda do |el| puts "#{el.first} = #{el.last}" end
h.each &test
# a = b

Alternatively, you can use Ruby's support for destructuring bind in parameter lists:

test = lambda do |(k, v)| puts "#{k} = #{v}" end
h.each &test
# a = b

Or, instead of using a lambda which has the same argument binding semantics as a method, you could use a Proc, which has the same argument binding semantics as a block, i.e. it will unpack a single Array argument into multiple parameter bindings:

test = proc do |k, v| puts "#{k} = #{v}" end
h.each &test
# a = b
like image 86
Jörg W Mittag Avatar answered Sep 28 '22 08:09

Jörg W Mittag


I still feel this is inconsistent syntax, I found the answer (but no apology) in another question Inconsistency of arity between Hash.each and lambdas

I switched it to

lambda do |(key, value)|

then I can pass in

hash.each &test

or I can call it directly with

test.call([key, value])

If someone has a better answer, or at least a succinct excuse why this is necessary. I'll gladly give them the points.

like image 23
DragonFax Avatar answered Sep 28 '22 07:09

DragonFax