我的Ruby数组是非确定性排序的

时间:2014-02-08 20:20:29

标签: ruby arrays sorting

当我对这个数组进行排序时,它会不断返回不同的排序顺序。

a = [ [0, 'cow'], [0, 'chicken'], [0, 'cat'], [0, 'goat'], [0, 'sheep'], [0, 'pig']]
a.push [1, 'dog']

a.sort_by! { |s| s[0] }
# => [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "pig"], [0, "sheep"], [0, "goat"], [1, "dog"]]
a.sort_by! { |s| s[0] }
# => [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "goat"], [0, "sheep"], [0, "pig"], [1, "dog"]]
a.sort_by! { |s| s[0] }
# => [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "pig"], [0, "sheep"], [0, "goat"], [1, "dog"]]
a.sort_by! { |s| s[0] }
# => [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "goat"], [0, "sheep"], [0, "pig"], [1, "dog"]]
a.sort_by! { |s| s[0] }

为什么我会收到不同的排序顺序?

3 个答案:

答案 0 :(得分:2)

Ruby使用Quicksort,这是一种不稳定的排序算法。这意味着在对数组进行排序后,相等元素的顺序可能会发生变化。

现在,如果使用sort_by而不是mutator方法sort_by!,则不会更改您开始使用的数组。因此,sort_by每次都会产生相同的结果。

当您使用sort_by!时,原始数组将替换为已排序的数组,因此元素可能会在每次迭代后更改其顺序。这意味着输出不是非确定性的,它只取决于输入。

答案 1 :(得分:2)

如果两个sort_by!相互跟随,那么您应该知道,由于sort_by!正在修改a,因此第二种方法不会向第一种方法提供相同的输入在将其提供给第二个sort_by!

之前
a = [ [0, 'cow'], [0, 'chicken'], [0, 'cat'], [0, 'goat'], [0, 'sheep'], [0, 'pig'], [1, 'dog']]

a.sort_by! { |s| s[0] }

=> [[0, "cow"],
 [0, "chicken"],
 [0, "cat"],
 [0, "pig"],
 [0, "sheep"],
 [0, "goat"],
 [1, "dog"]]

a成为最后一个数组。现在当你第二次排序时,你正在提供不同的输入。

现在,为了确认算法是确定性的,请执行以下操作:

sorted = []; 100.times { a = [ [0, 'cow'], [0, 'chicken'], [0, 'cat'], [0, 'goat'], [0, 'sheep'], [0, 'pig'], [1, 'dog']]; sorted << a.sort_by! { |s| s[0] } }

sorted.uniq.count
=> 1

答案 2 :(得分:-1)

请改用a = a.sort_by#sort_by!似乎不确定。

irb(main):132:0> a.sort_by { |s| s[0] }
=> [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "pig"], [0, "sheep"], [0, "goat"], [1, "dog"]]
irb(main):133:0> a.sort_by { |s| s[0] }
=> [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "pig"], [0, "sheep"], [0, "goat"], [1, "dog"]]
irb(main):134:0> a.sort_by { |s| s[0] }
=> [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "pig"], [0, "sheep"], [0, "goat"], [1, "dog"]]
irb(main):135:0> a.sort_by { |s| s[0] }
=> [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "pig"], [0, "sheep"], [0, "goat"], [1, "dog"]]
irb(main):136:0> a.sort_by { |s| s[0] }
=> [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "pig"], [0, "sheep"], [0, "goat"], [1, "dog"]]
irb(main):137:0> a.sort_by { |s| s[0] }
=> [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "pig"], [0, "sheep"], [0, "goat"], [1, "dog"]]
irb(main):138:0> a.sort_by { |s| s[0] }
=> [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "pig"], [0, "sheep"], [0, "goat"], [1, "dog"]]
irb(main):139:0> a.sort_by { |s| s[0] }
=> [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "pig"], [0, "sheep"], [0, "goat"], [1, "dog"]]
irb(main):140:0> a.sort_by { |s| s[0] }
=> [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "pig"], [0, "sheep"], [0, "goat"], [1, "dog"]]
irb(main):141:0> a.sort_by { |s| s[0] }
=> [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "pig"], [0, "sheep"], [0, "goat"], [1, "dog"]]
irb(main):142:0> a.sort_by! { |s| s[0] }
=> [[0, "cow"], [0, "chicken"], [0, "cat"], [0, "pig"], [0, "sheep"], [0, "goat"], [1, "dog"]]