重构:循环从嵌套数组中检索元素
Refactoring: Round-robin retrieve elements from nested arrays
我需要检查一个散列数组,每个散列包含一个标签和一个数据数组。最终结果将是一个串联的字符串,首先是标签,然后是与该标签对应的数据。
输入的哈希数组如下所示:
[{label: "first", data: [1, 2]}, {label: "second", data: [3, 4, 5]}, {label: "third", data: []}, {label: "fourth", data: [6]}]
在这个例子中,max_returns
会像这样高:10
def round_robin(arr, max_returns)
result = ''
i = 0 # number of grabbed elements
j = 0 # inner array position
k = 0 # outer array position
l = 0 # number of times inner array length has been exceeded
while i < max_returns do
if k >= arr.length
j += 1
k = 0
end
element = arr[k]
if element[:data].empty?
k += 1
next
end
if j >= element[:data].length
l += 1
k += 1
if l > arr.length && i < max_returns
break
end
next
end
result += element[:label] + ': ' + element[:data][j].to_s + ', '
i += 1
k += 1
end
result
end
根据上面给出的输入,输出应该是:
"first: 1, second: 3, fourth: 6, first: 2, second: 4, second: 5"
另外:max_returns
是检索结果总数的最大数量。因此,如果我的示例有一个 max_returns = 3
,那么输出将是:
"first: 1, second: 3, fourth: 6"
问题:是否有更好或更有效的方法以循环方式从多个数组中获取数据?
我不确定什么是循环法,但这是提供您需要的输出的解决方案:
基于初始数组元素删除的版本:
arr = [{label: "first", data: [1, 2]}, {label: "second", data: [3, 4, 5]}, {label: "third", data: []}, {label: "fourth", data: [6]}]
loop do
arr.each do |hash| # go through each hash
num = hash[:data].delete_at(0) # remove first element in data array
puts "#{hash[:label]}: #{num}" unless num.nil? # output it if it's not nil(means array was empty)
end
break if arr.map { |i| i[:data] }.flatten == [] # stop if all arrays are empty
end
不改变初始数组的版本:
arr = [{label: "first", data: [1, 2]}, {label: "second", data: [3, 4, 5]}, {label: "third", data: []}, {label: "fourth", data: [6]}]
max_data_size = arr.map { |i| i[:data] }.map(&:size).max
loop.with_index do |_, i|
arr.each do |hash|
num = hash[:data][i]
puts "#{hash[:label]}: #{num}" unless num.nil?
end
break if i >= max_data_size - 1
end
▶ input = [{label: "first", data: [1, 2]},
{label: "second", data: [3, 4, 5]},
{label: "third", data: []},
{label: "fourth", data: [6]}]
▶ max = input.max_by { |e| e[:data].size }[:data].size
▶ input.map do |h|
[[h[:label]] * max].flatten.zip h[:data] # make it N×M (for transpose)
end.transpose.map do |e|
e.reject { |_, v| v.nil? } # remove nils
end.flatten(1).map { |e| e.join ': ' }.join ', '
#⇒ "first: 1, second: 3, fourth: 6, first: 2, second: 4, second: 5"
如果没有最后两个连接,结果将是一个数组数组:
#⇒ [["first", 1], ["second", 3], ["fourth", 6],
# ["first", 2], ["second", 4], ["second", 5]]
arr = [{ label: "first", data: [1, 2] },
{ label: "second", data: [3, 4, 5] },
{ label: "third", data: [] },
{ label: "fourth", data: [6] }]
labels, data = arr.map { |h| [h[:label], h[:data].dup] }.transpose
#=> [["first", "second", "third", "fourth"], [[1, 2], [3, 4, 5], [], [6]]]
data.map(&:size).max.times.with_object([]) do |_,arr|
labels.each_index do |i|
d = data[i].shift
arr << "#{labels[i]}: #{d}" if d
end
end.join(', ')
#=> "first: 1, second: 3, fourth: 6, first: 2, second: 4, second: 5"
基准都是 运行 针对相同的数据。我 运行 每个答案针对四种不同的场景:
*_5
与原始数据相比 运行:852, 0, 0, 0
*_500
是 运行 针对相同的数据,但最多 500 returns。
*_2_5
是 运行 针对 4 个数组中的数据,大小分别为:656、137、0、59,总共 852 条记录。
*_2_500
是 运行 对抗 arr2,最大 return 为 500。
user system total real
OP_5: 0.000000 0.000000 0.000000 ( 0.000120)
Mudasobwa_5: 0.000000 0.000000 0.000000 ( 0.000108)
Cary_5: 0.010000 0.000000 0.010000 ( 0.011316)
Rustam_5: 0.000000 0.000000 0.000000 ( 0.000087)
Wand_5: 0.010000 0.000000 0.010000 ( 0.003761)
Stefan_5: 0.000000 0.000000 0.000000 ( 0.004007)
OP_500: 0.010000 0.010000 0.020000 ( 0.017235)
Mudasobwa_500: 0.010000 0.000000 0.010000 ( 0.006164)
Cary_500: 0.010000 0.000000 0.010000 ( 0.011403)
Rustam_500: 0.010000 0.000000 0.010000 ( 0.011884)
Wand_500: 0.010000 0.000000 0.010000 ( 0.003743)
Stefan_500: 0.000000 0.000000 0.000000 ( 0.002711)
OP_2_5: 0.000000 0.000000 0.000000 ( 0.000052)
Mudasobwa_2_5: 0.000000 0.000000 0.000000 ( 0.000140)
Cary_2_5: 0.010000 0.000000 0.010000 ( 0.008196)
Rustam_2_5: 0.000000 0.000000 0.000000 ( 0.000088)
Wand_2_5: 0.000000 0.000000 0.000000 ( 0.003338)
Stefan_2_5: 0.010000 0.000000 0.010000 ( 0.002597)
OP_2_500: 0.000000 0.000000 0.000000 ( 0.002211)
Mudasobwa_2_500: 0.000000 0.000000 0.000000 ( 0.006373)
Cary_2_500: 0.010000 0.000000 0.010000 ( 0.008455)
Rustam_2_500: 0.020000 0.000000 0.020000 ( 0.019453)
Wand_2_500: 0.010000 0.000000 0.010000 ( 0.004846)
Stefan_2_500: 0.000000 0.000000 0.000000 ( 0.003421)
OP_avg: 0.002500 0.002500 0.005000 ( 0.004904)
Mudasobwa_avg: 0.002500 0.000000 0.002500 ( 0.003196)
Cary_avg: 0.010000 0.000000 0.010000 ( 0.009843)
Rustam_avg: 0.007500 0.000000 0.007500 ( 0.007878)
Wand_avg: 0.007500 0.000000 0.007500 ( 0.003922)
Stefan_avg: 0.002500 0.000000 0.002500 ( 0.003184)
与我之前的基准相反,平均值表明 Stefan 的答案实际上是最快的,比 Mudasobwa 的答案快 0.000012 秒!
注意:我不得不编辑一些答案来模仿我原来的解决方案试图做的事情,所以在基准代码中添加了一些额外的东西目的。
此外,一些解决方案没有使用 max_returns
限制(或没有在限制处停止),这导致它们比其他解决方案花费的时间更长(当我最初问这个问题时,我责怪自己的 less-than-stellar 解释).我在选择答案时没有考虑 max_returns
限制,因为唯一符合它的解决方案是我的和 Wand 的(详见要点)。
可在此处找到执行这些基准测试的代码和示例数据:https://gist.github.com/scytherswings/65644610e20037bb948c
谢谢大家的回答!
这可行:
arr = [{ label: "first", data: [1, 3] },
{ label: "second", data: [3, 4, 5] },
{ label: "third", data: [] },
{ label: "fourth", data: [6] }]
results = []
arr.each do |h|
h[:data].each_with_index do |d, i|
results[i] ||= []
results[i] << "#{h[:label]}: #{d}"
end
end
results.flatten.join(', ')
#=> "first: 1, second: 3, fourth: 6, first: 3, second: 4, second: 5"
我需要检查一个散列数组,每个散列包含一个标签和一个数据数组。最终结果将是一个串联的字符串,首先是标签,然后是与该标签对应的数据。
输入的哈希数组如下所示:
[{label: "first", data: [1, 2]}, {label: "second", data: [3, 4, 5]}, {label: "third", data: []}, {label: "fourth", data: [6]}]
在这个例子中,max_returns
会像这样高:10
def round_robin(arr, max_returns)
result = ''
i = 0 # number of grabbed elements
j = 0 # inner array position
k = 0 # outer array position
l = 0 # number of times inner array length has been exceeded
while i < max_returns do
if k >= arr.length
j += 1
k = 0
end
element = arr[k]
if element[:data].empty?
k += 1
next
end
if j >= element[:data].length
l += 1
k += 1
if l > arr.length && i < max_returns
break
end
next
end
result += element[:label] + ': ' + element[:data][j].to_s + ', '
i += 1
k += 1
end
result
end
根据上面给出的输入,输出应该是:
"first: 1, second: 3, fourth: 6, first: 2, second: 4, second: 5"
另外:max_returns
是检索结果总数的最大数量。因此,如果我的示例有一个 max_returns = 3
,那么输出将是:
"first: 1, second: 3, fourth: 6"
问题:是否有更好或更有效的方法以循环方式从多个数组中获取数据?
我不确定什么是循环法,但这是提供您需要的输出的解决方案:
基于初始数组元素删除的版本:
arr = [{label: "first", data: [1, 2]}, {label: "second", data: [3, 4, 5]}, {label: "third", data: []}, {label: "fourth", data: [6]}]
loop do
arr.each do |hash| # go through each hash
num = hash[:data].delete_at(0) # remove first element in data array
puts "#{hash[:label]}: #{num}" unless num.nil? # output it if it's not nil(means array was empty)
end
break if arr.map { |i| i[:data] }.flatten == [] # stop if all arrays are empty
end
不改变初始数组的版本:
arr = [{label: "first", data: [1, 2]}, {label: "second", data: [3, 4, 5]}, {label: "third", data: []}, {label: "fourth", data: [6]}]
max_data_size = arr.map { |i| i[:data] }.map(&:size).max
loop.with_index do |_, i|
arr.each do |hash|
num = hash[:data][i]
puts "#{hash[:label]}: #{num}" unless num.nil?
end
break if i >= max_data_size - 1
end
▶ input = [{label: "first", data: [1, 2]},
{label: "second", data: [3, 4, 5]},
{label: "third", data: []},
{label: "fourth", data: [6]}]
▶ max = input.max_by { |e| e[:data].size }[:data].size
▶ input.map do |h|
[[h[:label]] * max].flatten.zip h[:data] # make it N×M (for transpose)
end.transpose.map do |e|
e.reject { |_, v| v.nil? } # remove nils
end.flatten(1).map { |e| e.join ': ' }.join ', '
#⇒ "first: 1, second: 3, fourth: 6, first: 2, second: 4, second: 5"
如果没有最后两个连接,结果将是一个数组数组:
#⇒ [["first", 1], ["second", 3], ["fourth", 6],
# ["first", 2], ["second", 4], ["second", 5]]
arr = [{ label: "first", data: [1, 2] },
{ label: "second", data: [3, 4, 5] },
{ label: "third", data: [] },
{ label: "fourth", data: [6] }]
labels, data = arr.map { |h| [h[:label], h[:data].dup] }.transpose
#=> [["first", "second", "third", "fourth"], [[1, 2], [3, 4, 5], [], [6]]]
data.map(&:size).max.times.with_object([]) do |_,arr|
labels.each_index do |i|
d = data[i].shift
arr << "#{labels[i]}: #{d}" if d
end
end.join(', ')
#=> "first: 1, second: 3, fourth: 6, first: 2, second: 4, second: 5"
基准都是 运行 针对相同的数据。我 运行 每个答案针对四种不同的场景:
*_5
与原始数据相比 运行:852, 0, 0, 0
*_500
是 运行 针对相同的数据,但最多 500 returns。
*_2_5
是 运行 针对 4 个数组中的数据,大小分别为:656、137、0、59,总共 852 条记录。
*_2_500
是 运行 对抗 arr2,最大 return 为 500。
user system total real
OP_5: 0.000000 0.000000 0.000000 ( 0.000120)
Mudasobwa_5: 0.000000 0.000000 0.000000 ( 0.000108)
Cary_5: 0.010000 0.000000 0.010000 ( 0.011316)
Rustam_5: 0.000000 0.000000 0.000000 ( 0.000087)
Wand_5: 0.010000 0.000000 0.010000 ( 0.003761)
Stefan_5: 0.000000 0.000000 0.000000 ( 0.004007)
OP_500: 0.010000 0.010000 0.020000 ( 0.017235)
Mudasobwa_500: 0.010000 0.000000 0.010000 ( 0.006164)
Cary_500: 0.010000 0.000000 0.010000 ( 0.011403)
Rustam_500: 0.010000 0.000000 0.010000 ( 0.011884)
Wand_500: 0.010000 0.000000 0.010000 ( 0.003743)
Stefan_500: 0.000000 0.000000 0.000000 ( 0.002711)
OP_2_5: 0.000000 0.000000 0.000000 ( 0.000052)
Mudasobwa_2_5: 0.000000 0.000000 0.000000 ( 0.000140)
Cary_2_5: 0.010000 0.000000 0.010000 ( 0.008196)
Rustam_2_5: 0.000000 0.000000 0.000000 ( 0.000088)
Wand_2_5: 0.000000 0.000000 0.000000 ( 0.003338)
Stefan_2_5: 0.010000 0.000000 0.010000 ( 0.002597)
OP_2_500: 0.000000 0.000000 0.000000 ( 0.002211)
Mudasobwa_2_500: 0.000000 0.000000 0.000000 ( 0.006373)
Cary_2_500: 0.010000 0.000000 0.010000 ( 0.008455)
Rustam_2_500: 0.020000 0.000000 0.020000 ( 0.019453)
Wand_2_500: 0.010000 0.000000 0.010000 ( 0.004846)
Stefan_2_500: 0.000000 0.000000 0.000000 ( 0.003421)
OP_avg: 0.002500 0.002500 0.005000 ( 0.004904)
Mudasobwa_avg: 0.002500 0.000000 0.002500 ( 0.003196)
Cary_avg: 0.010000 0.000000 0.010000 ( 0.009843)
Rustam_avg: 0.007500 0.000000 0.007500 ( 0.007878)
Wand_avg: 0.007500 0.000000 0.007500 ( 0.003922)
Stefan_avg: 0.002500 0.000000 0.002500 ( 0.003184)
与我之前的基准相反,平均值表明 Stefan 的答案实际上是最快的,比 Mudasobwa 的答案快 0.000012 秒!
注意:我不得不编辑一些答案来模仿我原来的解决方案试图做的事情,所以在基准代码中添加了一些额外的东西目的。
此外,一些解决方案没有使用 max_returns
限制(或没有在限制处停止),这导致它们比其他解决方案花费的时间更长(当我最初问这个问题时,我责怪自己的 less-than-stellar 解释).我在选择答案时没有考虑 max_returns
限制,因为唯一符合它的解决方案是我的和 Wand 的(详见要点)。
可在此处找到执行这些基准测试的代码和示例数据:https://gist.github.com/scytherswings/65644610e20037bb948c
谢谢大家的回答!
这可行:
arr = [{ label: "first", data: [1, 3] },
{ label: "second", data: [3, 4, 5] },
{ label: "third", data: [] },
{ label: "fourth", data: [6] }]
results = []
arr.each do |h|
h[:data].each_with_index do |d, i|
results[i] ||= []
results[i] << "#{h[:label]}: #{d}"
end
end
results.flatten.join(', ')
#=> "first: 1, second: 3, fourth: 6, first: 3, second: 4, second: 5"