【问题标题】:Splitting up an array into a hash将数组拆分为哈希
【发布时间】:2017-09-03 12:37:35
【问题描述】:

我有一个大约860项的数组,我想把它变成一个hash,数组结构是(Key1, value 1, value2, value 3, Key2, value 1, value 2, value 3... ........等等)除了在现实生活中它看起来像(彼得,150、39、345,约翰,123、450、402,玛丽,145、345、506...... ....)。原来这些是我一起转置的四个数组,所以我可以从 4 个独立的数组开始达到相同的最终目标。

我想要

Hash {Peter=> [150, 39, 345], John=>[123,450,402], Mary => [145,345,506] etc etc

我觉得应该有一个很好的简洁方法来做到这一点,但它让我望而却步,可能是因为我对 ruby​​ 的了解不够。

【问题讨论】:

  • 如果值数组的长度都相同,您不能迭代并将每个项目添加到适当的哈希条目中吗?您并没有真正说明原始数组是什么,但似乎跳过数组串联会更容易。

标签: arrays ruby ruby-hash


【解决方案1】:

试试这个

l = ['Peter', 150, 39, 345, 'John', 123, 450, 402, 'Mary', 145, 345, 506]

l.each_slice(4).to_a.inject({}){|acc, temp| acc[temp.first]=temp.last(3); acc}

#=>{"Peter"=>[150, 39, 345], "John"=>[123, 450, 402], "Mary"=>[145, 345, 506]}

【讨论】:

    【解决方案2】:
    arr = ['Peter', 150, 39, 345, 'John', 123, 450, 'Mary', 145, 345, 506, 222]
    
    arr.slice_before {|a| String === a }.
        each_with_object({}) {|(f,*rest), h| h[f] = rest}
      #=> {"Peter"=>[150, 39, 345], "John"=>[123, 450], "Mary"=>[145, 345, 506, 222]} 
    

    Enumerable#slice_before 在 Ruby v2.3 中首次亮相。也可以使用 Enumerable#slice_when,这是 v2.2 中的新功能。

    这里有另外几种适用于早期版本 Ruby 的方法。

    arr.chunk { |e| String === e }.
        each_slice(2).
        with_object({}) { |((_,(k)),(_,v)), h| h[k] = v }
    

    a = []
    enum = arr.to_enum
    loop do
      o = enum.next
      (String === o) ? a << [o,[]] : a.last.last << o
    end
    Hash[a]
    

    【讨论】:

      【解决方案3】:

      原来这四个数组是我转置在一起的,所以我可以从 4 个独立的数组开始达到相同的最终目标。

      我假设你有这样的开始:

      a = ["Peter", "John", "Mary"]
      b = [150, 123, 145]
      c = [39, 450, 345]
      d = [345, 402, 506]
      

      您可以通过zip 组合“值”数组:

      values = b.zip(c, d)
      #=> [[150, 39, 345], [123, 450, 402], [145, 345, 506]]
      

      并通过另一个zip添加“key”数组:

      a.zip(values)
      #=> [["Peter", [150, 39, 345]], ["John", [123, 450, 402]], ["Mary", [145, 345, 506]]]
      

      这已经是正确的结构,所以我们可以直接调用to_h

      a.zip(values).to_h
      #=> {"Peter"=>[150, 39, 345], "John"=>[123, 450, 402], "Mary"=>[145, 345, 506]}
      

      当然不需要中间变量,a.zip(b.zip(c, d)).to_h 返回的结果是一样的。

      【讨论】:

      • 或者你可以transpose而不是第二个zip:Hash[a.zip([b, c, d].transpose)]
      • ...或[a,b,c,d].transpose.each_with_object({}) { |(k,*v),h| h[k]=v }
      【解决方案4】:

      另一种方式:

      l = ['Peter', 150, 39, 345, 'John', 123, 450, 402, 'Mary', 145, 345, 506]
      
      Hash[*l.each_slice(4).flat_map { |a, *b| [a, b] }]
      #=> {"Peter"=>[150, 39, 345], 
      #    "John" =>[123, 450, 402], 
      #    "Mary" =>[145, 345, 506]}
      

      如果你已经有数组,解决方案会更简单:

      arrays = [array_1, array_2, array_3]
      Hash[*arrays.flat_map {|a, *b| [a, b]} ]
      #=> {"Peter"=>[150, 39, 345], "John"=>[123, 450, 402], "Mary"=>[145, 345, 506]}
      

      【讨论】:

        【解决方案5】:

        如果您知道数据总是以 4 个为一组:

        l = ['Peter', 150, 39, 345, 'John', 123, 450, 402, 'Mary', 145, 345, 506]
        h = {}
        l.each_slice(4).each do |chunk|
            h[chunk[0]] = chunk[1..chunk.length]
        end
        

        或者,如果您知道键始终是字符串:

        l = ['Peter', 150, 39, 345, 'John', 123, 450, 402, 'Mary', 145, 345, 506]
        h = {}
        current_key = ""
        l.each do |item|
            if item.is_a? String
                current_key = item
                h[item] = []
            else 
                h[current_key] << item 
            end 
        end
        

        基本上,您需要弄清楚如何对数组进行适当的切片,然后循环遍历。

        此外,如果您已经将它们作为单独的数组获取,您可以轻松地:

        array_1 = ['Peter', 150, 39, 345]
        array_2 = ['John', 123, 450, 402]
        array_3 = ['Mary', 145, 345, 506]
        h = {}    
        
        [array_1,array_2, array_3].each do |a|
            h[a[0]] = a[1:a.length]
        end
        
        # One line version:
        [array_1,array_2, array_3].map{|a| h[a[0]] = a[1..a.length]}
        

        我认为这是最干净的方法。

        【讨论】:

          猜你喜欢
          • 2017-02-22
          • 2015-02-08
          • 1970-01-01
          • 1970-01-01
          • 2016-05-21
          • 2012-10-29
          • 2016-11-04
          相关资源
          最近更新 更多