Array()应用于哈希?

时间:2013-08-22 13:13:42

标签: ruby arrays hash

最近我偶然发现了“The Elements of Style in Ruby #3: Make Sure Something Is an Array”。

TL; DR:Ruby中的方法Array()将您放入的任何内容转换为数组并尝试猜测应该是什么样的结果:

Array(1)     # => [1]
Array([1,2]) # => [1,2]
Array(nil)   # => []

那么Array({a: :b})会返回什么?我假设它返回一个数组,其哈希值为[{a: :b}]

但是,哈希会直接转换为数组:[:a, :b]

我不只是想将哈希放入数组([{a: :b}])。无论我放入什么内容,我都希望能够返回一个数组。Array()已经这样做了,但它以一种我不期望的方式将哈希转换为数组。

所以,基本上功能应如下所示:

NewFancyArrayMethod({a: :b}) # => [{a: :b}]
NewFancyArrayMethod([{a: :b}, {c: :d}]) # => [{a: :b}, {c: :d}]

第二部分已由Array()完成。

我知道我可以像values = [values] unless values.is_a? Array那样做,就像文章指出的那样。但是,我宁愿有一种方法可以将Array()的转换从我那里抽象出来。唯一的问题是Array()处理散列的方式与任何其他“单个”值(String,Integer,Object等)不同。我根本不希望针对不同的情况进行不同的处理。

4 个答案:

答案 0 :(得分:7)

  

那么Array({a: :b})会返回什么?我假设它返回一个数组,其哈希值为[{a: :b}]

你的假设是错误的。 Kernel#Array通过尝试(按此顺序)转换参数arg

  1. arg.to_ary
  2. arg.to_a
  3. 最后创建[arg]
  4. <强>示例:

    Array(1)        #=> [1]
    

    这是因为(3)。没有Fixnum#to_aryFixnum#to_a

    Array([1, 2])   #=> [1, 2]
    

    由于(1),这不会返回[[1, 2]]Array#to_ary返回self

    Array(nil)      #=> []
    

    由于(2),这不会返回[nil]。没有NilClass#to_ary但是NilClass#to_a“始终返回一个空数组。”

    Array({a: :b})  #=> [[:a, :b]]
    

    Array(nil)一样,由于(2),这不会返回[{a: :b}]。没有Hash#to_ary但是Hash#to_a“将hsh转换为[key,value]数组的嵌套数组。”

    Array(Time.now) #=> [33, 42, 17, 22, 8, 2013, 4, 234, true, "CEST"]
    

    这是Time#to_a返回... “时间值的十元素值数组”

    <强>结论:

    Kernel#Array按预期工作,Hash#to_a是罪魁祸首。 (或to_a一般)

      

    我希望有一个功能,无论我放入什么内容都会返回一个数组。

    HashArray是不同的对象。您可以检查类型(Kernel#Array也这样做):

    def hash_to_array(h)
      h.is_a?(Array) ? h : [h]
    end
    

    或者延伸Hash(甚至是Object)和Array

    class Hash # or Object
      def my_to_a
        [self]
      end
    end
    
    class Array
      def my_to_a
        self
      end
    end
    

    请参阅备选实施的评论。

答案 1 :(得分:2)

正如Frederick Cheung在推荐中指出的那样,方法Array#wrap正是我所希望的:

Array.wrap({a: :b})
# => [{a: :b}]

不幸的是,此方法只是ActiveSupport的一部分,因此无法在纯Ruby项目中使用。

答案 2 :(得分:1)

然后做如下的猴子补丁:

class Hash
  def fancyarraymethod
    [self]
  end
end
class Array
  def fancyarraymethod
    self
  end
end

{a: :b}.fancyarraymethod # => [{a: :b}]
[{a: :b}, {c: :d}].fancyarraymethod # => [{a: :b}, {c: :d}]

答案 3 :(得分:1)

如果您不知道它是一个数组或您正在使用的哈希,您可以使用flatten来防止在后者的情况下以嵌套数组结束。像这样:

[foo].flatten

# E.g.
foo = [{:a => :b}, {:c => :d}]
[foo] #=> [[{:a => :b}, {:c => :d}]] -- Nested, call flatten to fix that
[foo].flatten #=> [{:a => :b}, {:c => :d}]

foo = {:a => :b}
[foo] #=> [{:a => :b}] -- Not nested, call flatten anyway just in case
[foo].flatten #=> [{:a => :b}]

这也适用于字符串,整数和对象:

foo = 'bar'
[foo].flatten #=> ['bar']

foo = 1
[foo].flatten #=> [1]

foo = Object.new
[foo].flatten #=> [#<Object:0x00000100a8daf8>]

无论如何,你得到你想要的东西。