最近我偶然发现了“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等)不同。我根本不希望针对不同的情况进行不同的处理。
答案 0 :(得分:7)
那么
Array({a: :b})
会返回什么?我假设它返回一个数组,其哈希值为[{a: :b}]
。
你的假设是错误的。 Kernel#Array
通过尝试(按此顺序)转换参数arg
:
arg.to_ary
arg.to_a
[arg]
<强>示例:强>
Array(1) #=> [1]
这是因为(3)。没有Fixnum#to_ary
或Fixnum#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
一般)
我希望有一个功能,无论我放入什么内容都会返回一个数组。
Hash
和Array
是不同的对象。您可以检查类型(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>]
无论如何,你得到你想要的东西。