【问题标题】:Sorting sequentially按顺序排序
【发布时间】:2018-01-16 18:01:08
【问题描述】:

拥有一个包含两个不同元素的无序数组:

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

鉴于此示例,研究“排序”数组以使每四个 portraits 有一个 landscape

4 portraits
1 landscape
4 portraits
1 landscape
...

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

【问题讨论】:

  • 缺少一个“肖像”,您的预期输出是什么,要涵盖哪些场景?
  • 您可以收集横向和纵向条目的总数,并创建一个包含正确位置元素的新数组,而不是“排序”数组。这使您可以轻松处理没有足够“景观”可用的情况,并让您轻松控制输出顺序。
  • '有一个后备'。好的,回退是什么?

标签: arrays ruby sorting


【解决方案1】:

我猜如果“肖像”的数量与“风景”的数量不“一致”,那么它会将剩余的数量连续添加:

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

【讨论】:

    【解决方案2】:

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

    #!/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
    

    我假设每个对象不仅仅是一个“纵向”或“横向”开关,这就是我按顺序从数组中取出元素的原因。

    【讨论】:

    • Keith,我将您的解决方案添加到了基准测试中。我不知道我之前是怎么错过的。
    【解决方案3】:

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

    代码

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-28
      • 2010-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-25
      相关资源
      最近更新 更多