2013-02-21 55 views
4

如何将lambda传递给hash.each,以便我可以重新使用一些代码?如何将lambda传递给Hash.each?

> 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>' 
+0

感谢您的问题清理。 – DragonFax 2013-02-21 00:33:56

回答

10

each产生当前元素到块,如果lambda需要一个参数,而不是两个。在Hash的情况下,产生的元素是一个两元素Array,第一个元素是键,第二个元素是值。

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

或者,你可以用解构的参数列表绑定Ruby的支持:

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

或者,而不是使用lambda具有相同的参数结合语义的方法,您可以使用Proc,其具有相同的参数结合的语义块,即,其将解包的单个Array参数分成多个参数绑定:

test = proc do |k, v| puts "#{k} = #{v}" end 
h.each &test 
# a = b 
+0

我遇到的问题(在我找到答案之后)是,正如你可以在我的第二行代码中看到的那样,'each'显然需要一个带有2个参数的块。它只是没有带有2个参数的'lambda'。 WTF – DragonFax 2013-02-21 00:35:26

+0

'each' * always *产生* single *参数。 *总是*。没有例外。如果将一个* single *'Array'传递给一个带有多个*参数的块,那么'Array'将被解压到类似于并行赋值的参数中。但是这与'each'没有任何关系,只是基本的Ruby 101参数传递。 – 2013-02-21 00:39:18

+1

有魔力。如果可能,yield/block将打开一个**单个数组**。我无法在任何地方找到这个文件,也没有怀疑它。谢谢Jörg。 – DragonFax 2013-02-21 00:40:08

0

我还是觉得这是语法不一致,我发现了另一个问题的答案(但没有道歉) Inconsistency of arity between Hash.each and lambdas

我把它切换到

lambda do |(key, value)| 

然后我可以在

hash.each &test 

或者我可以直接打电话给

test.call([key, value]) 

如果有人有一个更好的答案,或者至少有一个简洁的借口,为什么这是必要的。我很乐意给他们分。

+0

您需要这种转换,因为'h.each'将每个对作为单个对象传递给一个数组。数组被传递给你的''''参数,并且你缺少一个'value'。用'(key,value)'表示法,它将数组的值正确地传递给它们中的每一个。就像当你写'a,b = [1,2]' – oldergod 2013-02-21 00:32:52

+0

我不确定你为什么觉得你在这里需要一个“借口”。 'each' * always *会产生一个* single *参数。你的lambda需要*两个*参数。显然,这是行不通的。 – 2013-02-21 00:33:24

0

看起来这是您从hash.each获得参数的方式。我只是在撬REPL测试了这个(如果你还没有使用过它,给它一个镜头。)

h.each { |k,v| 
    test.call(k,v)} 

each得到的值,并将它们放入拉姆达。