将多个逗号分隔值的Ruby散列转换为具有相同键的散列数组

o4tp2gmn  于 2023-02-08  发布在  Ruby
关注(0)|答案(4)|浏览(168)

什么是最有效和漂亮的方式来Map这一点:

{name:"cheese,test", uid:"1,2"}

改为:

[ {name:"cheese", uid:"1"},  {name:"test", uid:"2"} ]

应动态工作,例如:{ name:"cheese,test,third", uid:"1,2,3" }{name:"cheese,test,third,fourth", uid:"1,2,3,4", age:"9,8,7,6" }
最后我做了这个:

hash = {name:"cheese,test", uid:"1,2"}
results = []
length = hash.values.first.split(',').length
length.times do |i|
   results << hash.map {|k,v| [k, v.split(',')[i]]}
end
results.map{|e| e.to_h}

它是工作,但我不满意它,必须是一个更清洁和更"rubyst"的方式来做到这一点

bis0qfac

bis0qfac1#

def splithash(h)
  # Transform each element in the Hash...
  h.map do |k, v|
    # ...by splitting the values on commas...
    v.split(',').map do |vv|
      # ...and turning these into individual { k => v } entries.
      { k => vv }
    end
  end.inject do |a,b|
    # Then combine these by "zip" combining each list A to each list B...
    a.zip(b)

    # ...which will require a subsequent .flatten to eliminate nesting
    # [ [ 1, 2 ], 3 ] -> [ 1, 2, 3 ] 
  end.map(&:flatten).map do |s|
    # Then combine all of these { k => v } hashes into one containing
    # all the keys with associated values.
    s.inject(&:merge)
  end
end

可以像这样使用:

splithash(name:"cheese,test", uid:"1,2", example:"a,b")
# => [{:name=>"cheese", :uid=>"1", :example=>"a"}, {:name=>"test", :uid=>"2", :example=>"b"}]

乍看起来要复杂得多,但这可以处理任何数量的键。

b4lqfgs4

b4lqfgs42#

我可能会这样使用transposezip

hash = {name:"cheese,test,third,fourth", uid:"1,2,3,4", age:"9,8,7,6" }

hash.values.map{|x| x.split(",")}.transpose.map{|v| hash.keys.zip(v).to_h}

#=> [{:name=>"cheese", :uid=>"1", :age=>"9"}, {:name=>"test", :uid=>"2", :age=>"8"}, {:name=>"third", :uid=>"3", :age=>"7"}, {:name=>"fourth", :uid=>"4", :age=>"6"}]

要将其分解一点(为操作清晰起见,代码略有修改):

hash.values  
#=>  ["cheese,test,third,fourth", "1,2,3,4", "9,8,7,6"]
.map{|x| x.split(",")}  
#=>  [["cheese", "test", "third", "fourth"], ["1", "2", "3", "4"], ["9", "8", "7", "6"]]
.transpose  
#=>  [["cheese", "1", "9"], ["test", "2", "8"], ["third", "3", "7"], ["fourth", "4", "6"]]
.map do |v| 
  hash.keys  #=>  [[:name, :uid, :age], [:name, :uid, :age], [:name, :uid, :age], [:name, :uid, :age]]
  .zip(v)  #=>  [[[:name, "cheese"], [:uid, "1"], [:age, "9"]], [[:name, "test"], [:uid, "2"], [:age, "8"]], [[:name, "third"], [:uid, "3"], [:age, "7"]], [[:name, "fourth"], [:uid, "4"], [:age, "6"]]]
  .to_h  #=>  [{:name=>"cheese", :uid=>"1", :age=>"9"}, {:name=>"test", :uid=>"2", :age=>"8"}, {:name=>"third", :uid=>"3", :age=>"7"}, {:name=>"fourth", :uid=>"4", :age=>"6"}]
end
qyzbxkaa

qyzbxkaa3#

输入

hash={name:"cheese,test,third,fourth", uid:"1,2,3,4", age:"9,8,7,6" }

代码

p hash
    .transform_values { |v| v.split(',') }
    .map { |k, v_arr| v_arr.map { |v| [k, v] }
    }
    .transpose
    .map { |array| array.to_h }

产出

[{:name=>"cheese", :uid=>"1", :age=>"9"}, {:name=>"test", :uid=>"2", :age=>"8"}, {:name=>"third", :uid=>"3", :age=>"7"}, {:name=>"fourth", :uid=>"4", :age=>"6"}]
lnlaulya

lnlaulya4#

我们被赋予

h = { name: "cheese,test", uid: "1,2" }

这里有两种创建所需数组的方法。都不构造数组然后转换为散列。

第一名

首次计算

g = h.transform_values { |s| s.split(',') }
  #=> {:name=>["cheese", "test"], :uid=>["1", "2"]}

则计算

g.first.last.size.times.map { |i| g.transform_values { |v| v[i] } }
  #=> [{:name=>"cheese", :uid=>"1"}, {:name=>"test", :uid=>"2"}]

a = g.first
  #=> [:name, ["cheese", "test"]]
b = a.last
  #=> ["cheese", "test"]
b.size
  #=> 2

第二名

此方法不将哈希值转换为数组。

(h.first.last.count(',')+1).times.map do |i|
  h.transform_values { |s| s[/(?:\w+,){#{i}}\K\w+/] }
end
  #=> [{:name=>"cheese", :uid=>"1"}, {:name=>"test", :uid=>"2"}]

我们有

a = h.first
  #=> [:name, "cheese,test"]
s = a.last
  #=> "cheese,test"
s.count(',')+1
  #=> 2

我们可以用 free-spacing 模式表示正则表达式,使其自文档化。

/
(?:     # begin a non-capture group
  \w+,  # match one or more word characters followed by a comma  
)       # end the non-capture group
{#{i}}  # execute the preceding non-capture group i times
\K      # discard all matches so far and reset the start of the match
\w+     # match one or more word characters
/x      # invoke free-spacing regex definition mode

相关问题