这种方法强调计算效率。我计算数组中“肖像”的数量,并从中计算四人组的数量以及剩余的“肖像”和“风景”的数量。然后我使用这三个量来构造所需的数组,这不需要任何迭代步骤。
代码
def rearrange(arr)
nbr_portraits = arr.count("portrait")
nbr_landscapes = arr.size - nbr_portraits
groups_of_4_portraits = [nbr_portraits/4, nbr_landscapes].min
nbr_portraits -= 4 * groups_of_4_portraits
nbr_landscapes -= groups_of_4_portraits
[*[*["portrait"]*4, "landscape"]*groups_of_4_portraits,
*["portrait"] * nbr_portraits, *["landscape"] * nbr_landscapes]
end
示例
arr = ["portrait", "landscape", "portrait", "portrait", "portrait", "portrait",
"portrait", "portrait", "portrait", "portrait", "portrait", "portrait",
"portrait", "portrait", "portrait", "portrait", "portrait", "portrait",
"landscape", "landscape"]
rearrange arr
#=> ["portrait", "portrait", "portrait", "portrait", "landscape",
# "portrait", "portrait", "portrait", "portrait", "landscape",
# "portrait", "portrait", "portrait", "portrait", "landscape",
# "portrait", "portrait", "portrait", "portrait", "portrait"]
rearrange %w| portrait portrait portrait landscape portrait portrait
portrait portrait portrait portrait |
#=> ["portrait", "portrait", "portrait", "portrait", "landscape",
# "portrait", "portrait", "portrait", "portrait", "portrait"]
rearrange %w| portrait portrait portrait portrait portrait |
#=> ["portrait", "portrait", "portrait", "portrait", "portrait"]
rearrange %w| landscape landscape portrait landscape portrait |
#=> ["portrait", "portrait", "landscape", "landscape", "landscape"]
rearrange %w| landscape landscape landscape landscape |
#=> ["landscape", "landscape", "landscape", "landscape"]
rearrange []
#=> []
说明
以上arr的步骤如下。
nbr_portraits = arr.count("portrait")
#=> 17
nbr_landscapes = arr.size - nbr_portraits
#=> 3
groups_of_4_portraits = [nbr_portraits/4, nbr_landscapes].min
#=> 3
nbr_portraits -= 4 * groups_of_4_portraits
#=> 5
nbr_landscapes -= groups_of_4_portraits
#=> 0
b = ["portrait"] * 4
#=> ["portrait", "portrait", "portrait", "portrait"]
c = [*b, "landscape"]
#=> ["portrait", "portrait", "portrait", "portrait", "landscape"]
d = c * groups_of_4_portraits
#=> ["portrait", "portrait", "portrait", "portrait", "landscape",
# "portrait", "portrait", "portrait", "portrait", "landscape",
# "portrait", "portrait", "portrait", "portrait", "landscape"]
e = ["portrait"] * nbr_portraits
#=> ["portrait", "portrait", "portrait", "portrait", "portrait"]
f = ["landscape"] * nbr_landscapes
#=> []
[*d, *e, *f]
#=> ["portrait", "portrait", "portrait", "portrait", "landscape",
# "portrait", "portrait", "portrait", "portrait", "landscape",
# "portrait", "portrait", "portrait", "portrait", "landscape",
# "portrait", "portrait", "portrait", "portrait", "portrait"]
快速基准测试
在这里,我将上述方法与 Sebastian 和 Keith 的解决方案进行比较。结果不能直接比较,因为我们对问题的理解不同。基思和我把剩下的“肖像”或“风景”放在最后(“肖像”放在第一位),而塞巴斯蒂安只把剩下的“肖像”放在最后,丢弃任何左边-over“风景”。
require 'fruity'
np = 100
nl = 120
p (arr = [*["portrait"]*np, *["landscape"]*nl].shuffle).size
def sebastian(arr)
landscapes, portraits = arr.sort.slice_when { |a, b| a != b }.to_a
portraits.each_slice(4).flat_map.with_index { |e, i| e << landscapes[i] }.compact
end
def keith(arr)
ps, ls = arr.partition { |element| element == 'portrait' }
result = []
loop do
portrait_count = [4, ps.size].min
portrait_count.times { result << ps.shift }
landscape_count = [1, ls.size].min
landscape_count.times { result << ls.shift }
break if ps.empty? && ls.empty?
end
result
end
compare(
Sebastian: -> { sebastian arr },
Keith: -> { keith arr },
Cary: -> { rearrange arr }
)
Running each test 64 times. Test will take about 1 second.
Cary is faster than Keith by 5x ± 1.0
Keith is similar to Sebastian