数组方法与哈希

Array method versus hashes

我有一个对象(从 API 返回),它是散列或散列数组。如果它还不是一个数组,我想将它包含在一个数组中。

我尝试在其上应用 Array,它以预期的方式对数字或数组起作用:

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

但它失败了哈希值:

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

应该是[{:a=>1}].

或者,我可以添加类型检查:

responses = [responses] if responses.is_a?(Hash)

有更好的解决方案吗?

正如@mudasobwa 所建议的,[responses].flatten 可能是最干净的解决方案:

[{a: 1}].flatten           #=> [{:a=>1}]
[[{a: 1}, {b: 2}]].flatten #=> [{:a=>1}, {:b=>2}]

显然,这种不一致的响应格式不是一个很好的 API 设计;但不幸的是,这就是使用外部资源的本质......

如果上述数组中的每个散列确实代表一个唯一的对象,那么我将保留该代码原样。但是,如果您实际上对单个实体的每个属性都有不同的哈希值 (?!),那么您可以进一步清理 API 响应,如下所示:

[{a: 1}].flatten.reduce(:merge)           #=> {:a=>1}
[[{a: 1}, {b: 2}]].flatten.reduce(:merge) #=> {:a=>1, :b=>2}

I want to enclose it in an array if it is not already an array.

怎么样:

result = [result] unless result.is_a? Array

或者,使用 try_convert:

result = Array.try_convert(result) || [result]

ActiveSupport 引入了 Array#wrap 完全符合您的要求:

Array.wrap(responses)

出于多种原因,我个人更喜欢从不使用任何 Rails 助手,所以我会坚持使用 [responses].flatten,或者更好的是,使用最明确的版本:

case responses
when Hash then [responses]
when Array then responses
else raise "shit happened"
end