使用zip在ruby中转换哈希

5
以下哈希表是否有更简单的转置方法?我有一个可行的解决方案,但是转置方法难以阅读。用例是一组工作(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

2
我希望这里的每个问题都像这样。一个好的代码示例,带有测试。 - Yule
虽然很难理解您的描述,但我认为您在某些地方使用了“哈希”一词,而实际上应该是“数组”,这样对吗?(“作业哈希”,“日期哈希”)- 但最后的示例清楚地说明了问题。 :) - BroiSatse
感谢@Yule。提出问题本身就是一门艺术! - Kevin Monk
1
不太正确,@BroiSatse,但我能理解混淆的原因。在我的情况下,e2、e3等是从优秀的IceCube gem'job.occurrences_between(year_start, year_end).group_by(&:to_date)'中派生出来的。group_by创建了一个具有数组值的哈希表。 - Kevin Monk
@Yule 同意的情感。 - wurde
1个回答

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

它不会无谓地映射日期,并且可以双向工作(更改内部和外部键)。请告诉我您的想法 :)

太好了!用测试来提问的好处在于,你可以复制和粘贴代码,看看测试是否通过 :) 这比我的解决方案要干净得多。谢谢。➜ sd git:(PT98271602_scrollable_calendar) ✗ rspec ./stack_overflow_question.rb ..共计 0.00393 秒完成 2 个样例,0 失败 - Kevin Monk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接