按顺序排序

时间:2018-01-16 18:01:09

标签: arrays ruby sorting

有一个包含两个区别元素的无序数组:

arr = ["portrait", "landscape", "portrait", "portrait", "portrait", "portrait", "portrait", "portrait", "portrait", "portrait", "portrait", "portrait", "portrait", "portrait", "portrait", "portrait", "portrait", "portrait", "landscape", "landscape"]

在这个例子中,调查“排序”数组,每四个landscape有一个portraits

4 portraits
1 landscape
4 portraits
1 landscape
...

如果不是单线,那么实现这一目标的最短途径是什么?

3 个答案:

答案 0 :(得分:3)

我猜是否有"肖像"没有"#34;重合"与#34;景观的数量"然后它连续添加其余的:

arr = %w[portrait landscape portrait portrait portrait portrait portrait portrait portrait portrait portrait portrait portrait portrait portrait portrait portrait portrait landscape landscape]
landscapes, portraits =  arr.sort.slice_when { |a, b| a != b }.to_a
p portraits.each_slice(4).flat_map.with_index { |e, i| e << landscapes[i] }.compact

# ["portrait", "portrait", "portrait", "portrait", "landscape", "portrait", "portrait", "portrait", "portrait", "landscape", "portrait", "portrait", "portrait", "portrait", "landscape", "portrait", "portrait", "portrait", "portrait", "portrait"]

答案 1 :(得分:0)

不知道你的后备是什么意思,这里有一个如何实现你想要的例证。它可能不是最优雅的解决方案,但它很简单:

#!/usr/bin/env ruby

arr = (['P'] * 32 + ['L'] * 12).shuffle  # as an example
ps, ls = arr.partition { |element| element == 'P' }
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

puts result.each_slice(5) { |slice| p slice }

=begin
Outputs:
["P", "P", "P", "P", "L"]
["P", "P", "P", "P", "L"]
["P", "P", "P", "P", "L"]
["P", "P", "P", "P", "L"]
["P", "P", "P", "P", "L"]
["P", "P", "P", "P", "L"]
["P", "P", "P", "P", "L"]
["P", "P", "P", "P", "L"]
["L", "L", "L", "L"]
=end

我假设每件物品不仅仅是一幅“肖像”。或者&#39; landscape&#39;切换,这就是我按顺序从数组中获取元素的原因。

答案 2 :(得分:0)

这种方法强调计算效率。我计算数组中“肖像”的数量,并从中计算四个组的数量以及剩余的“肖像”和“风景”的数量。然后我使用这三个量来构造所需的数组,这不需要任何迭代步骤。

<强>代码

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"]   

快速基准

这里我将上述方法与塞巴斯蒂安和基思的解决方案进行比较。结果不能直接比较,因为我们对问题的理解不同。凯斯和我把任何剩下的“肖像”或“风景”放在最后(“肖像”的第一个),而塞巴斯蒂安只留下了剩下的“肖像”,最后丢弃了任何左边 - “风景”的。

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