【问题标题】:Sort items in cycle循环排序项目
【发布时间】:2016-04-12 14:03:15
【问题描述】:

我无法解释我在寻找什么,所以我将提供一个示例,假设我有这个数组:

[
  [1, 2],
  [1, 3],
  [1, 4],
  [2, 3],
  [2, 4],
  [3, 4]
]

我希望它循环通过第一列,而不是按第一列排序,所以它可以代替1, 1, 1, 2, 2, 31, 2, 3, 1, 2, 1

导致:

[
  [1, 2],
  [2, 3],
  [3, 4],
  [1, 3],
  [2, 4],
  [1, 4]
]

如果它可以循环遍历两列以尽可能避免连续出现两个数字,则更好的解决方案是将原始数组排序为:

[
  [1, 2],
  [3, 4],
  [1, 3],
  [2, 4],
  [1, 4],
  [2, 3]
]

导致每个内部数组的重复数字之间的最大间距(两列都被考虑在内)。

我希望我提供了足够的信息,我将不胜感激任何建议,到目前为止我还很无知,搜索没有给我任何帮助。

【问题讨论】:

  • 我不明白在这两列中循环,因此无法为此编写解决方案..
  • 相邻项目之间的距离是否重要,或者只是它们不同更好?
  • 骑自行车不能确保或最大化交替。例如,[1, 1, 1, 1, 2, 3, 4] 将导致 [1, 2, 3, 4, 1, 1, 1](末尾三个 1),尽管您可以不重复排列数字:[1, 2, 1, 3, 1, 4, 1]

标签: ruby-on-rails arrays ruby sorting multidimensional-array


【解决方案1】:

假设初始数组按第一个元素排序:

arr =
  [
    [1, 2],
    [1, 3],
    [1, 4],
    [2, 3],
    [2, 4],
    [3, 4],
  ]

res = []
arr_dup = arr.dup
remaining_values = arr_dup.map { |el| el[0] }
current_value = remaining_values.first
loop do
  arr_dup.each_with_index do |el, index|
    if el[0] >= current_value
      res << el
      current_value = remaining_values.select { |v| v > el[0] }.first || remaining_values.first
      remaining_values.delete_at(remaining_values.index(current_value))
      arr_dup.delete_at(index)
      break
    end
  end
  break if remaining_values.empty?
end

p arr #=> [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
p res #=> [[1, 2], [2, 3], [3, 4], [1, 3], [2, 4], [1, 4]]

几个测试:

[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4], [5, 1], [20, 2]] =>
[[1, 2], [2, 3], [3, 4], [5, 1], [20, 2], [1, 3], [2, 4], [1, 4]]

[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4], [5, 1], [5, 2], [20, 2]] =>
[[1, 2], [2, 3], [3, 4], [5, 1], [20, 2], [1, 3], [2, 4], [5, 2], [1, 4]]

【讨论】:

    【解决方案2】:

    你可以试试这个

    def func ary
      ret = []
      # group by first ones, and each sort by second ones
      a = ary.group_by{|i| i[0]}.map{|_,i| i.sort_by{|j| j[1]}}
      # add to ret
      (0...a.map{|i| i.size}.max).map{
        a.map{|i| ret << i.shift}
      }
      ret.compact
    end
    a = [[1, 2],[1, 3],[1, 4],[2, 3],[2, 4],[3, 4]]
    p func(a)
    #=> [[1, 2], [2, 3], [3, 4], [1, 3], [2, 4], [1, 4]]
    

    【讨论】:

      【解决方案3】:

      我将只解决您问题的第一部分,因为我不明白您所说的“如果它可以循环遍历两列以尽可能防止连续出现两个数字......” . “尽可能”这句话特别麻烦,因为它指的是一个未指定的标准。

      arr 成为您的数组。元素在您的示例中已排序,但如果不是,则第一步是:

      arr.sort!
      

      请参阅 Array#sort!Array#<=> 了解 Ruby 如何对元素为数组的数组进行排序。

      有很多方法可以获得所需的排序。这是一个使用Enumerable#chunk的:

      arr.chunk(&:first).flat_map {|_,a| a.map.with_index {|i,b| [b,i]}}.sort.map(&:last)
        #=> [[1, 2], [2, 3], [3, 4], [1, 3], [2, 4], [1, 4]]
      

      步骤如下:

      e = arr.chunk(&:first)
        #=> #<Enumerator: #<Enumerator::Generator:0x007fa01a8141d0>:each> 
      

      我们可以看到这个枚举器的元素,通过将其转换为数组,由Enumerator#each(调用Array#each)传递给块:

      e.to_a
        #=> [[1, [[1, 2], [1, 3], [1, 4]]], [2, [[2, 3], [2, 4]]], [3, [[3, 4]]]] 
      

      继续:

      f = e.flat_map { |_,a| a.map.with_index { |i,b| [b,i] } }
        #=> [[0, [1, 2]], [1, [1, 3]], [2, [1, 4]], [0, [2, 3]], [1, [2, 4]], [0, [3, 4]]] 
      g = f.sort
        #=> [[0, 1, 2], [0, 2, 3], [0, 3, 4], [1, 1, 3], [1, 2, 4], [2, 1, 4]] 
      g.map(&:last)
        #=> [[1, 2], [2, 3], [3, 4], [1, 3], [2, 4], [1, 4]] 
      

      让我们更仔细地看一下f的计算:

      h = e.flat_map
        #=> #<Enumerator: #<Enumerator: #<Enumerator::Generator:0x007fa01a8141d0>:each>:flat_map>
      h.to_a
        #=> [[1, [[1, 2], [1, 3], [1, 4]]], [2, [[2, 3], [2, 4]]], [3, [[3, 4]]]] 
      

      您可以将h 视为“复合”枚举器。

      h 的第一个值 [1, [[1, 2], [1, 3], [1, 4]]] 被传递给块,并由块变量使用 parallel(或 multiple赋值捕获

      i, a = h.next
        #=> [1, [[1, 2], [1, 3], [1, 4]]] 
      i #=> 1 
      a #=> [[1, 2], [1, 3], [1, 4]] 
      

      由于块计算中不使用i,因此习惯上将块变量替换为局部变量_

      我们现在可以进行块计算:

      a.map.with_index { |i,b| [b,i] } 
        #=> [[0, [1, 2]], [1, [1, 3]], [2, [1, 4]]]
      

      其余的计算类似地执行。

      【讨论】:

      • 我不会使用新的[index, x, y] 元素构建数组,而是通过[index, [x, y]] 保留/嵌入原始元素,即arr.chunk(&amp;:first).flat_map { |_, a| a.map.with_index { |b, i| [i, b] } }.sort.map(&amp;:last)
      • 好建议。我已经编辑了它。谢谢。读者:查看@Stefan 评论的另一种方式是,例如,如果a = [[2,[1,3]], [1,[2,4]]]a.sort.map(&amp;:last)a.map(&amp;:flatten).sort.map { |b| b.last(2) } 都产生相同的结果:[[2, 4], [1, 3]]。我在最初的回答中实际上是后者。
      猜你喜欢
      • 2012-02-24
      • 1970-01-01
      • 1970-01-01
      • 2019-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-02
      相关资源
      最近更新 更多