我有两个数组:
a=["joe","mark","mark","wilson","joe"]
b=[1,2,2,3,4]
我需要哈希:
h={"joe"=>[1,4],"mark"=>[2,2],"wilson"=>[3]}
主要问题是键重复并且可以有多个值。我尝试过zip
,inject
和map
,但我无法接近我需要的地方。我需要使用Ruby。
答案 0 :(得分:2)
我使用:
a=["joe","mark","mark","wilson","joe"]
b=[1,2,2,3,4]
a.zip(b).group_by{ |i,j| i }.map{ |k, v| [k, v.map(&:last)] }.to_h
# => {"joe"=>[1, 4], "mark"=>[2, 2], "wilson"=>[3]}
如果您不使用Ruby 2.1+,那么您将无法获得Array#to_h
,相反,您可以这样做:
Hash[a.zip(b).group_by{ |i,j| i }.map{ |k, v| [k, v.map(&:last)] }]
# => {"joe"=>[1, 4], "mark"=>[2, 2], "wilson"=>[3]}
以下是一些中间步骤:
a.zip(b) # => [["joe", 1], ["mark", 2], ["mark", 2], ["wilson", 3], ["joe", 4]]
a.zip(b).group_by{ |i,j| i } # => {"joe"=>[["joe", 1], ["joe", 4]], "mark"=>[["mark", 2], ["mark", 2]], "wilson"=>[["wilson", 3]]}
a.zip(b).group_by{ |i,j| i }.map{ |k, v| [k, v.map(&:last)] } # => [["joe", [1, 4]], ["mark", [2, 2]], ["wilson", [3]]]
此处展示的明星是group_by
,它收集符合给定条件的所有元素,在本例中,所有元素元素都与给定名称匹配。一旦这些被分组,那么它只是清理生成的数组并将其转换为哈希的情况。
答案 1 :(得分:0)
有几种方法可以做到这一点。这是两个。
<强>#1 强>
a = ["joe","mark","mark","wilson","joe"]
b = [1,2,2,3,4]
Hash[a.zip(b)
.group_by(&:first)
.values
.map { |arr| [arr.first.first, arr.map(&:last)] }]
#=> { "joe"=>[1, 4], "mark"=>[2, 2], "wilson"=>[3] }
使用Ruby 2.1:
a.zip(b)
.group_by(&:first)
.values
.map { |arr| [arr.first.first, arr.map(&:last)] }
.to_h
<强>#2 强>
a.zip(b)
.each_with_object({}) { |(name,val),h|
h.update({name=>[val]}) { |_,ov,nv| ov+nv } }
=> {"joe"=>[1, 4], "mark"=>[2, 2], "wilson"=>[3]}
第二种方法使用Hash#update(a.k.a。merge!
)的形式进行阻止。
答案 2 :(得分:0)
如果你想要实现的是(同一个)键有多个值,那么将值存储为双数组并进行一些修改可能有效:
class Hash
def add_key_value(key, value)
if self.has_key?(key)
self[key] << value
else
self[key] = [value]
end
end
end
h = Hash.new()
h.add_key_value('joe', [1,2])
p h #=> {"joe"=>[[1, 2]]}
h.add_key_value('joe', [3])
p h #=> {"joe"=>[[1, 2], [3]]}
h.add_key_value('mark', [4,5])
p h #=> {"joe"=>[[1, 2], [3]], "mark"=>[[4, 5]]}
h.add_key_value('mark', [1,2])
p h #=> {"joe"=>[[1, 2], [3]], "mark"=>[[4, 5], [1, 2]]}
答案 3 :(得分:0)
有两种变体,最快和最短:
def fastest(a, b)
result = {}
i = 0
a.each do |elem|
result[elem] ? result[elem] << b[i] : result[elem] = [b[i]]
i += 1
end
result
end
def shortest(a, b)
a.zip(b).group_by{ |i,j| i }.map{ |k, v| [k, v.map(&:last)] }.to_h
end
基准测试结果如下:
require 'benchmark/ips'
Benchmark.ips do |x|
%w(fastest shortest).each do |method|
x.report(method) { send method, ["joe","mark","mark","wilson","joe"], [1,2,2,3,4] }
end
end
fastest 185435.9 (±19.9%) i/s - 892388 in 5.017412s
shortest 93222.0 (±20.1%) i/s - 445398 in 5.011817s
答案 4 :(得分:0)
问题得到了很好的回答,但这是我的代码高尔夫尝试:)
a=["joe","mark","mark","wilson","joe"]
b=[1,2,2,3,4]
a.zip(b).reduce({}) {|o,(k,v)| (o[k] ||= []) << v; o}
一般的想法非常接近Tin Man's,但不是几个中间步骤,它只需要拉链阵列并将它们直接缩小为目标形式。