用拉链在红宝石中转置哈希

时间:2015-07-13 12:41:32

标签: ruby-on-rails ruby hash

以下哈希是否更容易转置?我有一个有效的解决方案,但转置方法很难阅读。用例是作业的散列(j1,j2,j3等)以及它们出现的日期(d1,d2,d3等等)。要求是采用按日期然后作业分组的事件(e1,e2,e3等等)的哈希值,并将它们转换为按作业然后日期分组的事件

我尝试使用#zip方法但是需要在j1:d1处注入nil,然后将它们从结果中删除。我也很难找到带有块参数的#zip的示例用法。我理解#zip with a block always returns nil但是因此我无法理解你将如何实际使用它。

require 'rspec'
require 'pry'

#     |  d1  |  d2  |  d3  |
#     ----------------------
# j1  |      |  e2  |  e3  |
# --------------------------
# j2  |  e4  |  e5  |  e6  |
# --------------------------
# j3  |  e7  |      |  e9  |
# --------------------------

def transpose(h)
  Hash[
    dates(h).map do |d|
      [
        d,
        Hash[ h.keys.map do |j|
          h[j][d] ? [j, h[j][d]] : nil
        end.compact ]
      ]
    end
  ]
end

def dates(h)
  h.values.map(&:keys).reduce(:|).sort
end

describe "transpose" do

  let(:starting) {
    {
      j1: { d2: :e2, d3: :e3 },
      j2: { d1: :e4, d2: :e5, d3: :e6 },
      j3: { d1: :e7, d3: :e9 }
    }
  }

  let(:transposed) {
    {
      d1: { j2: :e4, j3: :e7 },
      d2: { j1: :e2, j2: :e5 },
      d3: { j1: :e3, j2: :e6, j3: :e9 }
    }
  }

  it { expect(dates(starting)).to eq([:d1, :d2, :d3]) }
  it { expect(transpose(starting)).to eq(transposed) }
end

1 个答案:

答案 0 :(得分:2)

我已经重写了你的transpose方法,它应该更快更干净:

  def transpose(h)
    h.each_with_object({}) do |(outer, data), ret|
      data.each do |inner, event|
        ret[inner] = {} unless ret[inner]
        ret[inner][outer] = event
      end
    end
  end

它没有使用不必要的日期映射,并且两种方式都有效(更改内部和外部键)。让我知道你的想法:)。

相关问题