在 Ruby 中将嵌套哈希转为二维数组
Turn nested hash to two dimensional array in Ruby
我想编写一个可以接收嵌套散列和 return 二维数组的嵌套数组的方法。
hash_to_a({1=>2, 2=>3, {3=>4, 5=>6}=>7}) # [[1, 2], [2, 3], [[[3, 4], [5, 6]], 7]]
hash_to_a({{5=>{1=>3, 2=>4}}=>{7=>8}}) # [[[[5, [[1, 3], [2, 4]]]], [[7, 8]]]]
hash_to_a({5=>{1=>3, 2=>4}}) # [[5, [[1, 3], [2, 4]]]]
到目前为止我得到了这个:
def hash_to_a(a_hash)
result = []
a_hash.each { |k, v|
if k.is_a?(Hash)
result << k.to_a
else
result << k
end
if v.is_a?(Hash)
result << v.to_a
else
result << v
end
}
result
end
结果当然不尽如人意
hash_to_a({1=>2, 2=>3, {3=>4, 5=>6}=>7}) # [1, 2, 2, 3, [[3, 4], [5, 6]], 7]
hash_to_a({{5=>{1=>3, 2=>4}}=>{7=>8}}) # [[[5, {1=>3, 2=>4}]], [[7, 8]]]
hash_to_a({5=>{1=>3, 2=>4}}) # [5, [[1, 3], [2, 4]]]
我怎样才能达到想要的结果?我也试过回避,但就是想不通这个问题。
这个怎么样:
def deep_to_array(hash)
return hash unless hash.is_a?(Hash)
array = hash.to_a
array.each_with_index do |(k,v), index|
array[index][0] = deep_to_array(k)
array[index][1] = deep_to_array(v)
end
array
end
或者简明扼要:
def deep_to_array2(hash)
return hash unless hash.is_a?(Hash)
hash.map do |k,v|
[deep_to_array2(k), deep_to_array2(v)]
end
end
示例:
deep_to_array(({1=>2, 2=>3, {3=>4, 5=>6}=>7}))
=> [[1, 2], [2, 3], [[[3, 4], [5, 6]], 7]]
从没有嵌套的最简单的情况开始。
def hash_to_a(hash) # { 3 => 4 }
hash.map do |k, v| # 3, 4
[k, v] # [3, 4]
end
end
现在的问题是,对于更复杂的情况,我们不想 return 如果键或值是散列,我们想先从散列转换它。
def hash_to_a(hash)
hash.map do |k, v|
[hash_to_a(k), hash_to_a(v)]
end
end
这将与我们的简单案例一起爆炸,因为 3 没有方法 #map
。这是因为我们还没有处理基本情况。只需一行代码即可避免尝试映射非哈希值的内容。我们希望它的行为就像我们的第一次尝试一样:除了 return 键或值之外什么都不做。
def hash_to_a(object)
return object unless object.is_a? Hash
object.map do |k, v|
[hash_to_a(k), hash_to_a(v)]
end
end
我们完成了。
hash_to_a({1=>2, 2=>3, {3=>4, 5=>6}=>7}) # [[1, 2], [2, 3], [[[3, 4], [5, 6]], 7]]
hash_to_a({{5=>{1=>3, 2=>4}}=>{7=>8}}) # [[[[5, [[1, 3], [2, 4]]]], [[7, 8]]]]
hash_to_a({5=>{1=>3, 2=>4}}) # [[5, [[1, 3], [2, 4]]]]
你可以使用递归
def h_to_a(h)
h.map { |k,v| [k.is_a?(Hash) ? h_to_a(k) : k, v.is_a?(Hash) ? h_to_a(v) : v] }
end
h_to_a({ 1=>2, 2=>3, { 3=>4, 5=>6 }=>7 })
#=> [[1, 2], [2, 3], [[[3, 4], [5, 6]], 7]]
h_to_a({ { 5=>{ 1=>3, 2=>4 } }=>{ 7=>8 } })
#=> [[[[5, [[1, 3], [2, 4]]]], [[7, 8]]]]
h_to_a({ 5=>{ 1=>3, 2=>4 } })
#=> [[5, [[1, 3], [2, 4]]]]
这显然适用于任何级别的嵌套。
另一种变体(使用内置 Hash#to_a
)
作为class方法:
class Hash
def flatten_to_a
to_a.map {|i| i.is_a?(Array) ? i.map {|i| i.is_a?(Hash) ? i.flatten_to_a : i} : i}
end
end
作为独立方法:
def f2a hash
return hash unless Hash === hash
hash.to_a.map {|i| i.is_a?(Array) ? i.map {|i| i.is_a?(Hash) ? i.flatten_to_a : i} : i}
end
我想编写一个可以接收嵌套散列和 return 二维数组的嵌套数组的方法。
hash_to_a({1=>2, 2=>3, {3=>4, 5=>6}=>7}) # [[1, 2], [2, 3], [[[3, 4], [5, 6]], 7]]
hash_to_a({{5=>{1=>3, 2=>4}}=>{7=>8}}) # [[[[5, [[1, 3], [2, 4]]]], [[7, 8]]]]
hash_to_a({5=>{1=>3, 2=>4}}) # [[5, [[1, 3], [2, 4]]]]
到目前为止我得到了这个:
def hash_to_a(a_hash)
result = []
a_hash.each { |k, v|
if k.is_a?(Hash)
result << k.to_a
else
result << k
end
if v.is_a?(Hash)
result << v.to_a
else
result << v
end
}
result
end
结果当然不尽如人意
hash_to_a({1=>2, 2=>3, {3=>4, 5=>6}=>7}) # [1, 2, 2, 3, [[3, 4], [5, 6]], 7]
hash_to_a({{5=>{1=>3, 2=>4}}=>{7=>8}}) # [[[5, {1=>3, 2=>4}]], [[7, 8]]]
hash_to_a({5=>{1=>3, 2=>4}}) # [5, [[1, 3], [2, 4]]]
我怎样才能达到想要的结果?我也试过回避,但就是想不通这个问题。
这个怎么样:
def deep_to_array(hash)
return hash unless hash.is_a?(Hash)
array = hash.to_a
array.each_with_index do |(k,v), index|
array[index][0] = deep_to_array(k)
array[index][1] = deep_to_array(v)
end
array
end
或者简明扼要:
def deep_to_array2(hash)
return hash unless hash.is_a?(Hash)
hash.map do |k,v|
[deep_to_array2(k), deep_to_array2(v)]
end
end
示例:
deep_to_array(({1=>2, 2=>3, {3=>4, 5=>6}=>7}))
=> [[1, 2], [2, 3], [[[3, 4], [5, 6]], 7]]
从没有嵌套的最简单的情况开始。
def hash_to_a(hash) # { 3 => 4 }
hash.map do |k, v| # 3, 4
[k, v] # [3, 4]
end
end
现在的问题是,对于更复杂的情况,我们不想 return 如果键或值是散列,我们想先从散列转换它。
def hash_to_a(hash)
hash.map do |k, v|
[hash_to_a(k), hash_to_a(v)]
end
end
这将与我们的简单案例一起爆炸,因为 3 没有方法 #map
。这是因为我们还没有处理基本情况。只需一行代码即可避免尝试映射非哈希值的内容。我们希望它的行为就像我们的第一次尝试一样:除了 return 键或值之外什么都不做。
def hash_to_a(object)
return object unless object.is_a? Hash
object.map do |k, v|
[hash_to_a(k), hash_to_a(v)]
end
end
我们完成了。
hash_to_a({1=>2, 2=>3, {3=>4, 5=>6}=>7}) # [[1, 2], [2, 3], [[[3, 4], [5, 6]], 7]]
hash_to_a({{5=>{1=>3, 2=>4}}=>{7=>8}}) # [[[[5, [[1, 3], [2, 4]]]], [[7, 8]]]]
hash_to_a({5=>{1=>3, 2=>4}}) # [[5, [[1, 3], [2, 4]]]]
你可以使用递归
def h_to_a(h)
h.map { |k,v| [k.is_a?(Hash) ? h_to_a(k) : k, v.is_a?(Hash) ? h_to_a(v) : v] }
end
h_to_a({ 1=>2, 2=>3, { 3=>4, 5=>6 }=>7 })
#=> [[1, 2], [2, 3], [[[3, 4], [5, 6]], 7]]
h_to_a({ { 5=>{ 1=>3, 2=>4 } }=>{ 7=>8 } })
#=> [[[[5, [[1, 3], [2, 4]]]], [[7, 8]]]]
h_to_a({ 5=>{ 1=>3, 2=>4 } })
#=> [[5, [[1, 3], [2, 4]]]]
这显然适用于任何级别的嵌套。
另一种变体(使用内置 Hash#to_a
)
作为class方法:
class Hash
def flatten_to_a
to_a.map {|i| i.is_a?(Array) ? i.map {|i| i.is_a?(Hash) ? i.flatten_to_a : i} : i}
end
end
作为独立方法:
def f2a hash
return hash unless Hash === hash
hash.to_a.map {|i| i.is_a?(Array) ? i.map {|i| i.is_a?(Hash) ? i.flatten_to_a : i} : i}
end