【问题标题】:Turn nested hash to two dimensional array in Ruby在Ruby中将嵌套哈希转换为二维数组
【发布时间】:2017-11-22 07:35:09
【问题描述】:

我想写一个可以接收嵌套散列并返回二维数组的嵌套数组的方法。

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]]]

我怎样才能实现想要的结果?我也尝试过回避,但无法解决这个问题。

【问题讨论】:

    标签: arrays ruby algorithm multidimensional-array ruby-hash


    【解决方案1】:

    这个呢:

    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]] 
    

    【讨论】:

      【解决方案2】:

      从最简单的情况开始,没有嵌套。

      def hash_to_a(hash)  # { 3 => 4 }
        hash.map do |k, v| # 3, 4
          [k, v]           # [3, 4] 
        end
      end
      

      现在的问题是,对于更复杂的情况,如果它是散列,我们不想返回键或值,我们想先将其从散列转换。

      def hash_to_a(hash)
        hash.map do |k, v|
          [hash_to_a(k), hash_to_a(v)]
        end
      end
      

      这将在我们的简单案例中崩溃,因为 3 没有方法 #map。这是因为我们还没有处理基本情况。只需要一行代码来避免尝试映射不是哈希的东西。我们希望它的行为就像我们的第一次尝试一样:除了返回键或值之外什么都不做。

      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]]]]
      

      【讨论】:

        【解决方案3】:

        你可以使用递归

        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]]]]
        

        这显然适用于任何级别的嵌套。

        【讨论】:

          【解决方案4】:

          另一个变体(使用内置 Hash#to_a

          作为类方法:

          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
          

          【讨论】:

            猜你喜欢
            • 2015-08-12
            • 1970-01-01
            • 2018-10-27
            • 1970-01-01
            • 1970-01-01
            • 2016-05-08
            • 1970-01-01
            • 2020-01-30
            • 2013-11-13
            相关资源
            最近更新 更多