奇怪的乘数运算符行为在两个数组中进行散列组合

时间:2012-06-27 08:50:03

标签: ruby

我一直在寻找一种将两个数组转换为单个哈希的方法。我找到了类似的东西:

a1 = [1,2,3]
a2 = [?A, ?B, ?C]
Hash[*a1.zip(a2).flatten]

我认为这种语法有点奇怪,因为Hash[a1.zip a2]会做同样的事情。但更重要的是,我不了解*运算符的必要性。

我知道它将对象转换为数组或类似的东西(但显然不是[]所做的那样)。

执行时:

a = a1.zip(a2).flatten
 => [1, "A", 2, "B", 3, "C"]
a = *a1.zip(a).flatten
 => [1, "A", 2, "B", 3, "C"]

没有任何事情发生,而且对于我所知道的*运算符,这似乎是正常的行为。

那么,为什么

Hash[*a1.zip(a2).flatten]
 => {1=>"A", 2=>"B", 3=>"C"}
Hash[a1.zip(a).flatten]
 => {}

如果参数看起来相同,则返回不同的值?

我想我必须遗漏一些关于*运算符的内容。

感谢。

3 个答案:

答案 0 :(得分:4)

*运算符与数组一起使用时,它被称为 splat运算符

将其视为删除数组的第一级括号的运算符。这非常有用,因为您可以将数组转换为参数列表:

def stuff(x, y, z)
end

a = [1, 2, 3]
stuff(*a) # x,y,z gets assigned 1,2,3

同样适用于Hash[][]上的Hash运算符接受为参数:

  1. 键值对的参数列表:
    Hash["a", 1, "b", 2] #=> { "a" => 1, "b" => 2 }
  2. 表示键值的数组或数组对:
    Hash[ [["a", 1], ["b", 2]] ] #=> { "a" => 1, "b" => 2 }
  3. Hash[]并不接受普通的平面数组作为参数:

    Hash[ ["a", 1, "b", 2] ] #=> {}
    

    因此,考虑到这一点,加上我们对splat运算符的理解,您现在可以看到正在发生的事情:

    paired_array = a1.zip(a2)
    => [[1, "A"], [2, "B"], [3, "C"]]
    
    plain_array = a1.zip(a2).flatten
    => [1, "A", 2, "B", 3, "C"]
    
    # Per rule 2 above we know this works
    Hash[paired_array]
    => {1=>"A", 2=>"B", 3=>"C"} 
    
    # This won't work
    Hash[plain_array]
    => {}
    
    # But if we turn the plain_array into an argument list, 
    # then we know per rule 1 above that this will work
    Hash[*plain_array]
    => {1=>"A", 2=>"B", 3=>"C"} 
    

    现在你可能想知道当你做什么时嘿嘿:

    a = *plain_array
    => [1, "A", 2, "B", 3, "C"]
    

    由于我们知道splat运算符有效地删除了括号,我们得到了这个:

    a = 1, "A", 2, "B", 3, "C"
    

    ...有趣的是有效的Ruby代码,只是再次创建一个数组。

    您可以在rubyspec test case for the splat operator中阅读有关splat运算符的更多有趣内容。

答案 1 :(得分:2)

我认为你的例子中有一个错误,它应该是这样的:

Hash[a1.zip(a2).flatten] #=> {}
Hash[*a1.zip(a2).flatten] #=> {1=>"A", 2=>"B", 3=>"C"}

分配模式下的splat运算符将数组转换为多个参数:

duck, cow, pig = *["quack","mooh","oing"] #=> ["quack","mooh","oing"]

实际上它与

完全相同
duck, cow, pig = ["quack","mooh","oing"] #=> ["quack","mooh","oing"]

但是从documentation可以看出Hash [...]接收到多个参数,因此splat运算符有助于分配这些多个参数。

答案 2 :(得分:1)

这不是那么神秘:

a1 = [1,2,3]
a2 = [?A, ?B, ?C]

p Hash[*a1.zip(a2).flatten] #{1=>"A", 2=>"B", 3=>"C"}

*将数组转换为纯粹的参数列表。

但为什么不使用这种语法?

p Hash[a1.zip(a2)]# {1=>"A", 2=>"B", 3=>"C"}

嗯,自Ruby 1.9.2以来它是新的。你的例子可能比较老了。