【问题标题】:How do I pass a lambda to Hash.each?如何将 lambda 传递给 Hash.each?
【发布时间】:2013-02-21 00:20:49
【问题描述】:

如何将 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>'

【问题讨论】:

  • 感谢您清理问题。

标签: ruby lambda


【解决方案1】:

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

或者,您可以使用Proc,而不是使用与方法具有相同参数绑定语义的lambda,它具有与块相同的参数绑定语义,即它将解压缩单个@987654328 @argument 成多个参数绑定:

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

【讨论】:

  • 我遇到的问题(在我找到答案之后)是,正如您在我的第二行代码中看到的那样,each 显然需要一个带有 2 个参数的块。它只是无法使用带有 2 个参数的 lambda。见鬼
  • each always 产生一个 single 参数。 总是。没有例外。如果您将 single Array 传递给带有 多个 参数的块,则 Array 将被解压缩到参数中,类似于并行分配。但这与each 没有任何关系,这只是基本的 Ruby 101 参数传递。
  • 这就是魔法。如果可能,yield/block 会解压缩一个单个数组。我在任何地方都找不到这个记录,也没有怀疑。谢谢约尔格。
  • 是的,Procs 具有与块相同的参数传递语义(宽松的数量检查,数组解包),而 lambdas 具有与方法相同的参数传递语义(严格的数量检查,无需拆包)。
【解决方案2】:

我仍然觉得这是语法不一致,我在另一个问题中找到了答案(但没有道歉) Inconsistency of arity between Hash.each and lambdas

我换成

lambda do |(key, value)|

那我可以进去

hash.each &test

或者我可以直接调用它

test.call([key, value])

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

【讨论】:

  • 您需要这种转换,因为h.each 将每一对作为单个对象(一个数组)传递。该数组已传递给您的key 参数,而value 缺少一个。使用(key, value) 表示法,它将数组的值正确地传递给它们中的每一个。比如你写a, b = [1, 2]
  • 我不知道你为什么觉得你需要一个“借口”。 each always 产生一个 single 参数。您的 lambda 接受 两个 参数。显然,这是行不通的。
【解决方案3】:

我遇到过一个类似的情况,我不想打印,而是在对值进行一些操作后返回一个键值对......上面的解决方案适用于你只想打印但它可能会变得棘手您需要返回这些键值对的哈希。所以我认为这可能会有所帮助

我用它解决了caesar-cipher难题

hash1 = {"a" => 1, "b" => 2, "c" => 3}
test = lambda {|k,v| true ? {k => v+2} : {k => v+1} }

在将其映射到哈希后,它将返回一个哈希数组(这里是有趣的地方)

hash2 = hash1.map(&test)   # [{"a"=>3}, {"b"=>4}, {"c"=>5}]

我们可以将其转换为 ruby​​stically!

hash2.inject(:merge!)   # {"a" => 3, "b" => 4, "c" => 5}

宾果游戏!!!对?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-31
    • 1970-01-01
    相关资源
    最近更新 更多