【问题标题】:Swap hash keys with values and convert keys to symbols in Ruby?用值交换哈希键并将键转换为 Ruby 中的符号?
【发布时间】:2014-05-23 10:23:46
【问题描述】:

这是输入哈希:

p Score.periods #{"q1"=>0, "q2"=>1, "q3"=>2, "q4"=>3, "h1"=>4, "h2"=>5}

这是我当前用值交换键的代码,同时将键转换为符号:

periods = Score.periods.inject({}) do |hsh,(k,v)|
  hsh[v] = k.to_sym
  hsh
end

结果如下:

p periods #{0=>:q1, 1=>:q2, 2=>:q3, 3=>:q4, 4=>:h1, 5=>:h2}

看起来我的代码很笨拙,我在这里做的事情不应该花 4 行。有没有更简洁的方法来写这个?

【问题讨论】:

标签: ruby loops hash


【解决方案1】:

你可以这样做:

Hash[periods.values.zip(periods.keys.map(&:to_sym))]

或者,如果您正在使用 to_h 可用于数组的 Ruby 版本,您可以这样做:

periods.values.zip(periods.keys.map(&:to_sym)).to_h

上面的两个例子所做的是将原始哈希的键和值组成数组。请注意,哈希的字符串键通过将to_sym 作为Proc 传递给map 映射到符号:

periods.keys.map(&:to_sym)
# => [:q1, :q2, :q3, :q4, :h1, :h2]

periods.values
# => [0, 1, 2, 3, 4, 5]

然后它将它们压缩成一个[value, key] 对的数组,其中values 的每个对应元素都与其在keys 中的对应键匹配:

periods.values.zip(periods.keys.map(&:to_sym))
# => [[0, :q1], [1, :q2], [2, :q3], [3, :q4], [4, :h1], [5, :h2]]

然后可以使用Hash[array]array.to_h 将该数组转换回散列。

【讨论】:

  • 不错。我那里也有一个 to_sym 函数,所以我认为它必须是这个,Score.periods.values.zip(Score.periods.keys.map{|k| k.to_sym}).to_h
  • @appleLover 我把它写得更短了,看看吧。
  • @appleLover 是 Score 来自 Ruby on Rails 的 Active Record 关系吗?如果是,请注意不要在两次调用Score.periods 时多次查询数据库。我不确定在你的情况下它是否真的会被查询两次,只是你可能想要仔细检查你没有做的事情。
【解决方案2】:

最简单的方法是:

data = {"q1"=>0, "q2"=>1, "q3"=>2, "q4"=>3, "h1"=>4, "h2"=>5}

Hash[data.invert.collect { |k, v| [ k, v.to_sym ] }]

Hash[] 方法将键/值对数组转换为实际的哈希。在这种情况下非常方便。

如果您使用的是 Ruby on Rails,这可能会更容易:

data.symbolize_keys.invert

【讨论】:

  • 你应该可以使用to_h而不是Hash[],这取决于你的Ruby版本,对吧?
  • 我相信这是在 Ruby 2.1 中添加的,所以是的,也有这个选项。
  • 你可以跳过invert: Hash[data.collect { |k, v| [ v, k.to_sym] }]
  • 我突然想到我的评论也适用于我的回答。
【解决方案3】:
h = {"q1"=>0, "q2"=>1, "q3"=>2, "q4"=>3, "h1"=>4, "h2"=>5}

h.each_with_object({}) { |(k,v),g| g[v] = k.to_sym  }
  #=> {0=>:q1, 1=>:q2, 2=>:q3, 3=>:q4, 4=>:h1, 5=>:h2} 

步骤如下(为了 Ruby 新手的利益)。

enum = h.each_with_object({})
  #=> #<Enumerator: {0=>"q1", 1=>"q2", 2=>"q3", 3=>"q4",
  #                  4=>"h1", 5=>"h2"}:each_with_object({})>

将由枚举器生成并传递给块的元素可以通过使用Enumerable#entriesEnumerable#to_a 将枚举器转换为数组来查看。

enum.entries
  #=> [[["q1", 0], {}], [["q2", 1], {}], [["q3", 2], {}],
  #    [["q4", 3], {}], [["h1", 4], {}], [["h2", 5], {}]] 

继续,

enum.each { |(k,v),g| g[v] = k.to_sym  }
  #=> {0=>:q1, 1=>:q2, 2=>:q3, 3=>:q4, 4=>:h1, 5=>:h2}

在最后一步,Enumerator#eachenum 生成的第一个元素传递给块,并分配三个块变量。考虑传递给块的enum 的第一个元素以及三个块变量的相关值计算。 (我必须先执行enum.rewind 来重新初始化enum,因为上面的each 将枚举数置于其末尾。参见Enumerator#rewind

(k, v), g = enum.next
  #=> [["q1", 0], {}]
k #=> "q1"
v #=> 0
g #=> {}

Enumerator#next。因此,块计算是

g[v] = k.to_sym
  #=> :q1

因此,

g #=> {0=>:q1}

enum 的下一个元素被传递给块并执行类似的计算。

(k, v), g = enum.next
  #=> [["q2", 1], {0=>:q1}] 
k #=> "q2" 
v #=> 1 
g #=> {0=>:q1} 
g[v] = k.to_sym
  #=> :q2 
g #=> {0=>:q1, 1=>:q2} 

其余计算类似。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-02-05
    • 2016-08-14
    • 1970-01-01
    • 2017-10-27
    • 1970-01-01
    • 1970-01-01
    • 2011-10-19
    • 1970-01-01
    相关资源
    最近更新 更多