我正在实现自定义排序。有一个太空船操作员<=>
处理数组的排序:
myArray.sort { |a, b| a <=> b }
a <=> b
大于1
时,b
返回a
,并且两个元素被交换。a <=> b
等于0
时,a
返回b
,并且两个元素保持原始位置。a <=> b
小于-1
时,a
返回b
,并且两个元素保持原始位置。所以我用一个例子进行了测试:
myArray = [2, 1, 7, 9, 3, 8, 0]
myArray.sort { |a, b| 1 <=> 1 } # making it always return 0
#=> [9, 1, 7, 2, 3, 8, 0]
结果不是我期望的。在我的期望中,当飞船操作员返回0
时,每个元素都将停留在原始位置。由于在上面的示例中,宇宙飞船运算符始终返回0
,因此该数组应保持不变。但是,结果与原始数组不同。
我有误会吗?
已更新:
以下是我上面的问题来自何处的想法。
最初,我试图按对象的属性对对象进行排序(假设属性为status
)。
例如
myObjects = [obj1, obj2,..., objn] # the objects are ordered by create_time already
myObjects.sort{|a,b|
case a.status
when 'failed'
x = 1
when 'success'
x = 0
when 'pending'
x = -1
end
case b.status
when 'failed'
y = 1
when 'success'
y = 0
when 'pending'
y = -1
end
x <=> y # compare two objects (a and b) by the status
}
myObjects
已按created_time
排序,但我想再次按每个对象的status
对其进行排序。
例如
两个具有相同created time
的对象(此处仅考虑小时和分钟,而忽略秒)将根据其状态再次排序,从而将状态为failed
的对象放在末尾数组。
以上代码中的x
和y
值将取决于对象的状态,
比较x
和y
以确定顺序。如果两个对象的状态相同(x == y
,则元素应保持在同一位置,因为它们已经按created_time
进行了排序,无需再次对其进行排序。
当两个对象的状态均为success
时,x <=> y
将返回0
。
但是根据一些评论,太空飞船运营商返回的比较值0
似乎输出了不可预测的顺序。
如果myObjects
包含所有状态均为相同的元素怎么办?自x == y
起,这将导致飞船操作员始终返回0。
在我的期望中,myObjects
应该保持相同的顺序,因为状态都是相同的,在我的情况下使用宇宙飞船运算符时应该如何纠正?
非常感谢大家的帮助!
答案 0 :(得分:9)
您关于排序方式的假设不正确。根据{{3}} connectedCallback() {
var parent = this.getRootNode().host
console.log( parent.localNode ) // my-list
}
不稳定:
不能保证结果稳定。当两个元素的比较返回0时,元素的顺序是不可预测的。
答案 1 :(得分:7)
Array#sort
使用Quicksort算法,该算法不稳定,当元素“相等”时会产生这种行为。
原因在于每步选择和移动 pivot 元素,在这种情况下,ruby实现似乎在中间选择了pivot(但可以选择不同的方式)。
这是您的示例中发生的情况:
9
上选择了sorted_left + [pivot] + sorted_right
,左边为空,因此枢轴移动了Ruby core documentation提到了这一点:
当两个元素的比较返回0时,元素的顺序是不可预测的。
此外,太空飞船运营商<=>
在这里没有任何作用,您可以致电myArray.sort{0}
以获得相同的效果。
从更新的问题来看,很明显,您要按两个属性进行排序,这可以通过几种方法完成:
方法1:您可以发明一个同时考虑两个值并对其进行排序的指标/键:
status_order = { 'success' => 1, 'failed' => 2, 'pending' => 3 }
myObjects.sort_by{|o| "#{status_order[o.status]}_#{o.created_time}" }
就极端性能而言,这不是最佳选择,但更短。
方法2:通过编写如下比较规则来隐式组合键:
status_order = { 'success' => 1, 'failed' => 2, 'pending' => 3 }
status_order.default = 0
myObjects.sort{|a,b|
if a.status == b.status
a.created_time <=> b.created_time
else
status_order[a.status] <=> status_order[b.status]
end
}
答案 2 :(得分:4)
工作原理
myArray = [2, 1, 7, 9, 3, 8, 0]
myArray.sort { |a, b| a <=> b }
#=> [0, 1, 2, 3, 7, 8, 9]
myArray.sort { |a, b| b <=> a }
#=> [9, 8, 7, 3, 2, 1, 0]
如果比较结果始终为0
,则无法对元素进行排序。这是很合逻辑的。
但是,文档在这种情况下明确指出元素的顺序是不可预测的。这就是为什么结果与旧数组不同的原因。
但是,我在Ruby 2.5.1中复制了您的情况,并返回了旧数组
myArray = [2, 1, 7, 9, 3, 8, 0]
myArray.sort { |a, b| 1 <=> 1 }
#=> [2, 1, 7, 9, 3, 8, 0]
您的代码中还有一个误解。你写了
myArray #=> [9, 1, 7, 2, 3, 8, 0]
但是实际上Array#sort
不会更改数组,只有Array#sort!
会更改数组。