在Ruby中,我该如何转换它:
{"1"=>{"id"=>1, "album"=>"album1", "track"=>"track1"},
"2"=>{"id"=>2, "album"=>"album1", "track"=>"track2"},
"3"=>{"id"=>3, "album"=>"album2", "track"=>"track1"},
"4"=>{"id"=>4, "album"=>"album2", "track"=>"track2"}}
进入这个:
{"album1"=>
{"1"=>{"id"=>1, "album"=>"album1", "track"=>"track1"},
"2"=>{"id"=>2, "album"=>"album1", "track"=>"track2"}},
"album2"=>
{"3"=>{"id"=>3, "album"=>"album2", "track"=>"track1"},
"4"=>{"id"=>4, "album"=>"album2", "track"=>"track2"}}}
以最有效的方式。
第一种是iTunes存储曲目信息的格式。最后一个是我需要在“专辑”级别处理曲目的格式。我一整天都在盯着这个,并且不擅长Ruby,已经失败了。感谢您关于hash kung-foo的教程。
修改
当我在等待主持人决定这是否合适时,我得到了一个解决方案:
album_tracks = {}
titles = []
tracks_hash.each do |album_id, album_hash|
titles << album_hash["album"] if !titles.include? album_hash["album"]
end
titles.each do |title|
tracks = {}
tracks_hash.each do |album_id, album_hash|
tracks[album_id] = album_hash if title == album_hash["album"]
end
albums_hash[title] = tracks
end
我猜测有一种更有效的策略涉及某种映射,不需要两次传递整个哈希?
答案 0 :(得分:2)
您的输出可以通过对group_by
的非常直接的调用来实现,然后进行一些转换以将结果转换为哈希值:
albums = {"1"=>{"id"=>1, "album"=>"album1", "track"=>"track1"},
"2"=>{"id"=>2, "album"=>"album1", "track"=>"track2"},
"3"=>{"id"=>3, "album"=>"album2", "track"=>"track1"},
"4"=>{"id"=>4, "album"=>"album2", "track"=>"track2"}}
albums.group_by { |k,v| v['album'] }.map { |k,v| [k, v.to_h] }.to_h
# => {
# "album1"=> {
# "1"=>{"id"=>1, "album"=>"album1", "track"=>"track1"},
# "2"=>{"id"=>2, "album"=>"album1", "track"=>"track2"}
# },
# "album2"=>{
# "3"=>{"id"=>3, "album"=>"album2", "track"=>"track1"},
# "4"=>{"id"=>4, "album"=>"album2", "track"=>"track2"}
# }
#}
关键是要了解Enumerable
上哪些方法可用于将一个结构转换为另一个结构(即group_by
和map
),然后知道Ruby允许您自由地将数组转换为哈希值反之亦然。
第一个调用albums.group_by { |k,v| v['album'] }
生成正确的外部哈希结构,但值的格式为[[key1, value1], [key2, value2], ...]
。 Ruby允许您使用{key1: value1, key2: value2}
将相同的结构转换回to_h
哈希。
答案 1 :(得分:0)
这应该可以解决问题。
album_tracks = tracks_hash.each_with_object({}) do |(album_id, album_hash), album_tracks|
album_tracks[album_hash['album']] ||= {}
album_tracks[album_hash['album']][album_id] = album_hash
end
答案 2 :(得分:0)
一种方法是使用Hash#update(aka merge!
)的形式,它使用一个块来确定合并的两个哈希中存在的键的值。
h = { "1"=>{ "id"=>1, "album"=>"album1", "track"=>"track1" },
"2"=>{ "id"=>2, "album"=>"album1", "track"=>"track2" },
"3"=>{ "id"=>3, "album"=>"album2", "track"=>"track1" },
"4"=>{ "id"=>4, "album"=>"album2", "track"=>"track2" } }
h.each_with_object({}) do |(k,v),g|
g.update(v["album"]=>{ k=>v}) { |_,o,n| o.update(n) }
end
#=> {"album1"=>{"1"=>{"id"=>1, "album"=>"album1", "track"=>"track1"},
# "2"=>{"id"=>2, "album"=>"album1", "track"=>"track2"}},
# "album2"=>{"3"=>{"id"=>3, "album"=>"album2", "track"=>"track1"},
# "4"=>{"id"=>4, "album"=>"album2", "track"=>"track2"}}}
请注意update
的参数
v["album"]=>{ k=>v}
是哈希
的简写{ v["album"]=>{ k=>v} }
步骤:
enum = h.each_with_object({})
#=> #<Enumerator: {"1"=>{"id"=>1, "album"=>"album1", "track"=>"track1"},
# "2"=>{"id"=>2, "album"=>"album1", "track"=>"track2"},
# "3"=>{"id"=>3, "album"=>"album2", "track"=>"track1"},
# "4"=>{"id"=>4, "album"=>"album2", "track"=>"track2"}}:
# each_with_object({})>
将enum
的第一个元素传递给块,并使用分解分配块变量:
(k,v),g = enum.next
#=> [["1", {"id"=>1, "album"=>"album1", "track"=>"track1"}], {}]
k #=> "1"
v #=> {"id"=>1, "album"=>"album1", "track"=>"track1"}
g #=> {}
然后执行块计算:
g.update(v["album"]=>{ k=>v }) { |_,o,n| o.update(n) }
#=> {}.update("album1"=>{ "1"=>{"id"=>1, "album"=>"album1", "track"=>"track1"})
# { |_,o,n| o.update(n) }
#=> {"album1"=>{ "1"=>{ "id"=>1, "album"=>"album1", "track"=>"track1"}}}
合并了两个哈希,{}
和
{ "album1"=>{ "1"=>{"id"=>1, "album"=>"album1", "track"=>"track1"} }
没有共同的键,因此该块不用于计算任何值。
然后将enum
的下一个元素传递给块:
(k,v),g = enum.next
#=> [["2", {"id"=>2, "album"=>"album1", "track"=>"track2"}], {}]
k #=> "2"
v #=> {"id"=>2, "album"=>"album1", "track"=>"track2"}
g #=> {"album1"=>{"1"=>{"id"=>1, "album"=>"album1", "track"=>"track1"}}}
现在更新计算
g.update(v["album"]=>{ k=>v }) { |_,o,n| o.update(n) }
#=> g.update("album1"=>{ "2"=> {"id"=>2, "album"=>"album1", "track"=>"track2"})
我们正在构建的哈希,
g #=> { "album1"=>{"1"=>{"id"=>1, "album"=>"album1", "track"=>"track1" } } }
并且哈希被合并,
{ "album1"=>{ "2"=> {"id"=>2, "album"=>"album1", "track"=>"track2"} } }
都有密钥"album1"
,因此该块用于确定该密钥的值:
在块中
{ |_,o,n| o.update(n) }
我们有
o #=> { "1"=>{"id"=>1, "album"=>"album1", "track"=>"track1" } }
n #=> { "2"=>{"id"=>2, "album"=>"album1", "track"=>"track2" } }
所以
{ "1"=>{"id"=>1, "album"=>"album1", "track"=>"track1"} }.
update({ "2"=>{"id"=>2, "album"=>"album1", "track"=>"track2"} })
#=> { "1"=>{"id"=>1, "album"=>"album1", "track"=>"track1" },
# "2"=>{"id"=>2, "album"=>"album1", "track"=>"track2"} }
哈希g
现在是
g #=> {"album1"=>{"1"=>{"id"=>1, "album"=>"album1", "track"=>"track1"},
# "2"=>{"id"=>2, "album"=>"album1", "track"=>"track2"}}}
其余的计算方法类似。