【问题标题】:How does `sort` work when `<=>` is not an order relation?当 `<=>` 不是顺序关系时,`sort` 是如何工作的?
【发布时间】:2016-02-11 17:52:34
【问题描述】:

假设我定义了元素之间的&lt;=&gt; 关系,使其不是顺序关系(即,它不满足一些自反性、反对称性、传递性)。

class Scissors
  def <=> other
    case other
    when Scissors then 0
    when Paper then 1
    when Rock then -1
    end
  end
end

class Paper
  def <=> other
    case other
    when Scissors then -1
    when Paper then 0
    when Rock then 1
    end
  end
end

class Rock
  def <=> other
    case other
    when Scissors then 1
    when Paper then -1
    when Rock then 0
    end
  end
end

当我在这些元素之间调用sort(非Schwartzian比较)时,我得到了一定的结果:

scissors = Scissors.new
paper = Paper.new
rock = Rock.new

[rock, paper, scissors].sort
# =>
# [
#   #<Rock:0x007f7a64ffaa10>,
#   #<Paper:0x007f7a64ffaa38>,
#   #<Scissors:0x007f7a64ffaa60>
# ]

[scissors, paper, rock].sort
# =>
# [
    #<Scissors:0x007f7a64ffaa60>,
    #<Rock:0x007f7a64ffaa10>,
    #<Paper:0x007f7a64ffaa38>
# ]

sort 在这种情况下遵循什么逻辑?

【问题讨论】:

  • 看起来这将是非常特定于实现的。我们可以假设您专门指的是 MRI 吗?
  • 排序谓词需要严格的排序,如果比较 scissors-paper-rock,情况并非如此。对于一个大组,分区排序将选择一个元素,然后将所有小于它的元素放在一侧,将所有大于另一侧的元素放在一边,所以你最终会得到所有的文件,然后是所有的剪刀,然后是所有的石头,如果枢轴Picked 是一个剪刀对象。如果一个不同的人最终会在中间。

标签: ruby sorting


【解决方案1】:

要了解 Ruby 比较数组中元素的顺序,请使用下一个技巧:

[rock, paper, scissors].sort {|x,y| p [x,y]; x<=>y}
[#<Paper:0x000000080407d8>, #<Scissors:0x00000007e91c70>]
[#<Rock:0x000000080fce88>, #<Paper:0x000000080407d8>]
#=> [#<Rock:0x000000080fce88>, #<Paper:0x000000080407d8>, #<Scissors:0x00000007e91c70>]

[scissors, paper, rock].sort {|x,y| p [x,y]; x<=>y}
[#<Paper:0x000000080407d8>, #<Rock:0x000000080fce88>]
[#<Scissors:0x00000007e91c70>, #<Rock:0x000000080fce88>]
#=> [#<Scissors:0x00000007e91c70>, #<Rock:0x000000080fce88>, #<Paper:0x000000080407d8>]

如您所见,Ruby 从数组的末尾开始比较。 在每次迭代中,Ruby 都会比较对象,如果第二个对象小于第一个对象,它们将被交换。

【讨论】:

  • 有点不清楚。在第一种情况下,第二种比较是纸上谈兵,它们在原始数组中是相邻的。第二种情况,第二种比较是剪刀石头布,在原数组的两端。
  • [scissors, paper, rock] 在第一次迭代后转换为[scissors, rock, paper],因为paperrock 多,并且Ruby 交换了它。 Ruby 就地修改数组以节省内存,我认为
  • 这并不能解释为什么[3, 2, 1] 可以排序为[1, 2, 3]。根据你的解释,首先比较21,得到[3, 1, 2]。然后,31 应该进行比较,得到[1, 3, 2]。
  • 恕我直言,Ruby 对如此小的数组使用冒泡排序是有道理的。因为对于小N,冒泡排序比快速排序或合并排序更有效。如果 Ruby 先检查输入的大小,然后根据数组中元素的数量使用不同的算法,我不会感到惊讶。
  • sort! 文档看起来像 Ruby 使用快速排序。还有stackoverflow.com/q/855773/128421
猜你喜欢
  • 1970-01-01
  • 2013-09-06
  • 1970-01-01
  • 1970-01-01
  • 2011-08-09
  • 1970-01-01
  • 1970-01-01
  • 2021-08-02
  • 2015-11-05
相关资源
最近更新 更多