我有两个数组,我正在使用Ruby中的Hash创建一个键值值。在将两个阵列拉入键值对并在重复器的密钥名称前添加诸如" 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"}
看来直接已附加了代码段
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"}
您基本上只需要跟踪哈希构建时的状态,当您发现冲突时,就需要创建一个新密钥。这捕获了一般方法:
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
(不要这样做。)
这真的很简单。
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个约翰,这就是为什么while循环在功能内部的原因。
这是创建所需哈希的一种方法。请注意,在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"]}
请参阅枚举#every_with_index,enumerable#group_by,hash#transform_values 1 和数组#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中的新事物。
此代码不那么可读,但紧凑且功能风格。
概念上与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) }
使用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