我有两个数组,我正在使用Ruby中的哈希创建键-值对。将两个数组压缩成键值对并在重复项的键名前面添加前缀“ A-”之类的时候,如何检测重复键?
我正在使用.zip合并两个数组,并将一个数组设为键,另一个数组设为值
[0] = "David"
[1] = "John"
[2] = "Alex"
[3] = "Sam"
[4] = "Caleb"
[5] = "David"
[6] = "John"
[7] = "Alex"
[8] = "Sam"
[0] = "1"
[1] = "2"
[2] = "3"
[3] = "4"
[4] = "5"
[5] = "6"
[6] = "7"
[7] = "8"
[8] = "9"
name_number_key_value_pair_hash = first_names.zip(numbers).to_h
puts(name_number_key_value_pair_hash)
预期:
{"David"=>"1", "John"=>"2", "Alex"=>"3", "Sam"=>"4", "Caleb"=>"5", "A-David"=>"6", "A-John"=>"7", "A-Alex"=>"8", "A-Sam"=>"9"}
实际:
{"David"=>"6", "John"=>"7", "Alex"=>"8", "Sam"=>"9", "Caleb"=>"5"}
答案 0 :(得分:3)
看起来很简单附带了代码段
names = %w[David John Alex Sam Caleb David John Alex Sam]
numbers = %w[1 2 3 4 5 6 7 8 9]
key_pair = {}
names.each_with_index do |name, index|
name = "A-#{name}" if key_pair[name]
key_pair[name] = numbers[index]
end
它生成预期的输出:
{"David"=>"1", "John"=>"2", "Alex"=>"3", "Sam"=>"4", "Caleb"=>"5", "A-David"=>"6", "A-John"=>"7", "A-Alex"=>"8", "A-Sam"=>"9"}
答案 1 :(得分:0)
基本上,您只需要在构建散列时跟踪散列的状态,并在发现冲突时创建一个新密钥。这捕获了一般方法:
def hash_with_prefixes(a, b, prefixes)
kv_pairs = a.zip(b)
prefixes = prefixes.to_enum
result_hash = {}
kv_pairs.each do |initial_key, value|
final_key = initial_key
while result_hash.include? final_key
final_key = "#{pfx.next}-#{initial_key}"
end
prefixes.rewind
result_hash[final_key] = value
end
result_hash
rescue StopIteration
fail "Insufficient prefixes to provide unique keys for input lists."
end
以轻微的清晰性为代价,您也可以将其写成较短的形式:
def hash_with_prefixes(a, b, prefixes)
pi = Hash[a.map {|k| [k, prefixes.lazy.map {|p| "#{p}-#{k}"}]}]
a.zip(b).inject({}) {|h, kv| h[h.include?(kv[0]) ? pi[kv[0]].next : kv[0]] = kv[1]; h}
rescue StopIteration
fail "Insufficient prefixes to provide unique keys for input lists."
end
(不要这样做。)
答案 2 :(得分:0)
这真的很简单。
names = ["John","John", "John", "David", "David", "Susan", "Sue"]
numbers = ["1", "2", "3", "4", "5", "6","7"]
def uniq_hash_keys(names, numbers)
hash = {}
names.each_with_index do |name,i|
if hash[name]
prefix = 'A1-'
key = prefix + name
while hash[key]
version = prefix.match(/A(\d+)-.*/i)[1].to_i
prefix = "A#{version + 1}-"
key = prefix + name
end
name = key
end
hash[name] = numbers[i]
end
hash
end
此函数产生:
{
"John"=>"1",
"A1-John"=>"2",
"A2-John"=>"3",
"David"=>"4",
"A1-David"=>"5",
"Susan"=>"6",
"Sue"=>"7"
}
请注意,有3个John,这就是while循环位于函数内部的原因。
答案 3 :(得分:0)
使用zip
和each_with_object
names = %w[David John Alex Sam Caleb David John Alex Sam]
numbers = %w[1 2 3 4 5 6 7 8 9]
names.zip(numbers).each_with_object({}) do |(name, number), hash|
key = hash.key?(name) ? "A-#{name}" : name
hash[key] = number
end
答案 4 :(得分:0)
这是创建所需哈希的一种方法。请注意,在arr1
中,“约翰”出现了3次。
arr1 = ["David", "John", "Alex", "Sam", "Caleb",
"David", "John", "Alex", "John", "Sam"]
arr2 = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
prefixes =
arr1.each_with_object({}) do |s,h|
if h.key?(s)
prefix = "A-"
(h[s].size-1).times { prefix = prefix.next }
h[s] << prefix
else
h[s] = ['']
end
end
#=> {"David"=>["", "A-"], "John"=>["", "A-", "B-"],
# "Alex"=>["", "A-"], "Sam"=>["", "A-"],
# "Caleb"=>[""]}
arr1.map { |s| "#{prefixes[s].shift}#{s}" }.zip(arr2).to_h
#=> {"David"=>"1", "John"=>"2", "Alex"=>"3", "Sam"=>"4",
# "Caleb"=>"5", "A-David"=>"6", "A-John"=>"7",
# "A-Alex"=>"8", "B-John"=>"9", "A-Sam"=>"10"}
请注意,"A-".next #=> "B-"
和"Z-".next #=> "AA-"
。
备用数据结构
您可能希望考虑一种不同的数据结构,该数据结构可以返回
{"David"=>["1", "6"], "John"=>["2", "7", "9"],
"Alex" =>["3", "8"], "Sam" =>["4", "10"], "Caleb"=>["5"]}
您可以按照以下步骤进行操作。
arr1.each_with_index.
group_by(&:first).
transform_values { |v| arr2.values_at(*v.map(&:last)) }
#=> {"David"=>["1", "6"], "John"=>["2", "7", "9"],
# "Alex" =>["3", "8"], "Sam" =>["4", "10"],
# "Caleb"=>["5"]}
请参见Enumerable#each_with_index,Enumerable#group_by,Hash#transform_values 1 和Array#values_at。 v.map(*:last)
在这里与v.map { |arr| arr.last }
相同。
步骤如下。
a = arr1.each_with_index
#=> #<Enumerator: ["David", "John", "Alex", "Sam",
# "Caleb", "David", "John", "Alex", "John", "Sam"]:
# each_with_index>
我们可以看到此枚举器将其转换为数组所生成的值。
a.to_a
#=> [["David", 0], ["John", 1], ["Alex", 2], ["Sam", 3],
# ["Caleb", 4], ["David", 5], ["John", 6], ["Alex", 7],
# ["John", 8], ["Sam", 9]]
继续
b = a.group_by(&:first)
#=> {"David"=>[["David", 0], ["David", 5]],
# "John"=> [["John", 1], ["John", 6], ["John", 8]],
# "Alex"=> [["Alex", 2], ["Alex", 7]],
# "Sam"=> [["Sam", 3], ["Sam", 9]],
# "Caleb"=>[["Caleb", 4]]}
b.transform_values { |v| arr2.values_at(*v.map(&:last)) }
#=> {"David"=>["1", "6"], "John"=>["2", "7", "9"],
# "Alex"=> ["3", "8"], "Sam"=> ["4", "10"], "Caleb"=>["5"]}
对于最后一步,将哈希b
的第一个值传递到块,并将块变量分配给该值。
v = b.values.first
#=> [["David", 0], ["David", 5]]
块的计算如下。
c = v.map(&:last)
#=> [0, 5]
arr2.values_at(*c)
#=> arr2.values_at(0, 5)
#=> ["1", "6"]
对于传递到该块的b
的其余每个值,计算都相似。
1。 Ruby MRI v2.4中的新功能。
答案 5 :(得分:0)
此代码可读性较差,但紧凑而实用。
从概念上讲,它与rahul mishra代码https://stackoverflow.com/a/54697573/2109121
相同names = %w[David John Alex Sam Caleb David John Alex Sam]
numbers = %w[1 2 3 4 5 6 7 8 9]
result = names.zip(numbers).reduce({}) { |a, (b, c)| a.merge(a.key?(b) ? "A-#{b}" : b => c) }