Sorting 使用多个订单条件重新排序项目
场景:Sorting 使用多个订单条件重新排序项目,sorting,Sorting,场景: 照片列表 每张照片都有以下属性 id 序列号 main\u photo\u位 第一张照片的main\u photo\u位设置为1(所有其他照片都是0) 照片按序列号排序(任意) 主照片不一定具有最低的序列号(排序前) 见下表: id, sequence_number, main_photo_bit 1 10 1 2 5 0 3 20
- 照片列表
- 每张照片都有以下属性
id
序列号
main\u photo\u位
- 第一张照片的
main\u photo\u位设置为
(所有其他照片都是1
)0
- 照片按序列号排序(任意)
- 主照片不一定具有最低的序列号(排序前)
id, sequence_number, main_photo_bit
1 10 1
2 5 0
3 20 0
现在,您需要通过更改序列号和主照片位来更改顺序
排序后的要求:
- 第一张照片的序列号未更改
- 第一张照片的序列号是最低的
- 尽可能少的变化
- id 1:新的
和序列号
设置为主照片位
0
- id 2:旧的第一张照片(id 2)
和序列号
设置为主照片位
1
- id 3:什么也没发生
- id 1:新的
大于第一张照片和序列号
到主照片位
0
- id 2:新的
大于新生成的第二个序列号
序列号
- id 3:旧的第一张照片
和序列号
设置为主照片位
1
我希望尽可能少的更新是因为我想将其同步到外部服务,这是一项非常昂贵的操作。
我已经得到了该算法的一个工作原型,但在一些边缘情况下它失败了。因此,我想知道是否有其他(更好的)方法来解决这个问题,而不是修补它(这可能会奏效,但会变得比现在更复杂)。
在我的版本中(简而言之),它订购照片(更改序列号),并交换主照片位,但这并不足以解决所有情况。据我所知,一个好的解决方案不仅可以最大限度地减少更改(因为更新是一项代价高昂的操作),但也要尽量减少未来的变化,因为越来越多的照片被重新排序。我首先添加一个临时字段
dirty
,以指示行是否必须更改:
id, sequence_number, main_photo_bit, dirty
1 10 1 false
2 5 0 false
3 20 0 false
4 30 0 false
5 31 0 false
6 33 0 false
如果有序列号
小于第一个的行,它们肯定必须更改(要么获得更高的数字,要么成为第一个)。让我们将它们标记为脏的:
id, sequence_number, main_photo_bit, dirty
2 5 0 true
(如果第一个序列号是否最低并不重要,请跳过此步骤)
现在让我们看看照片列表,因为它们应该出现在结果中(根据问题,从任何地方到任何地方,只有一张照片改变了位置)。粗体的脏的:
[1,2,3,4,5,6]#原始订单
[2,1,3,4,5,6]#示例1:从第二名到第一名
[3,1,2,4,5,6]#示例2:第3名到第1名
[1,2,4,3,5,6]#示例3:第三至第四名
[1,3,2,4,5,6]#示例4:第三至第二名
首先要做的是确保第一个元素的序列号最低。如果它没有改变位置,那么根据定义它已经改变了,否则旧的第一个应该被标记为脏的,清除它的main\u photo\u位
,新的应该接收这些值到它自己
此时,第一个元素应该有一个固定的序列号,每个脏元素的值都可以随意更改(因为它无论如何都必须更改,所以最好更改为有用的值)。在继续之前,我们必须确保只有更改脏行才能解决问题,或者如果更多行也需要脏行,则必须确保有可能解决问题。这只是一个确定每对干净行之间的间隔是否足够大以适应它们之间脏行的数量的问题:
[10, D, 20, 30, 31, 33] # Original ordering (the first is dirty, but fixed)
[10, D, 20, 30, 31, 33] # Example 1: 2nd to 1st place (ok: 10 < ? < 20)
[10, D, D, 30, 31, 33] # Example 2: 3rd to 1st place (ok: 10 < ? < ? < 30)
[10, D, 30, D, 31, 33] # Example 3: 3rd to 4th place (NOT OK: 30 < ? < 31)
[10, D, 30, D, D, 33] # must mark 5th as dirty too (ok: 30 < ? < ? < 33)
[10, D, D, 30, 31, 33] # Example 4: 3rd to 2nd place (ok)
[10,D,20,30,31,33]#原始订单(第一个是脏的,但已修复)
[10,D,20,30,31,33]#示例1:第二至第一名(ok:10<?<20)
[10,D,D,30,31,33]#示例2:第三名到第一名(确定:10<30)
[10,D,30,D,31,33]#示例3:第三至第四名(不合格:30<?<31)
[10,D,30,D,D,33]#必须将第五个标记也标记为脏(正常:30<?<?<?<33)
[10,D,D,30,31,33]#示例4:第三到第二名(ok)
现在只需为脏行分配新的序列号。一个天真的解决方案是只增加前一个,但更好的方法是将它们设置为尽可能等距的。通过这种方式,未来的重新排序需要更少的更改的可能性更大(换句话说,为了避免像示例3这样的问题,因为一些序列号
s彼此太近,所以必须更新比需要更多的行):
[strong>10,15,20,30,31,33]#示例1:从第二名到第一名
[10,16,23,30,31,33]#示例2:第三名到第一名
[10,20,30,31,32,33]#示例3:第三至第四名
[10,16,id, sequence_number, main_photo_bit, dirty
2 5 0 true
[10, D, 20, 30, 31, 33] # Original ordering (the first is dirty, but fixed)
[10, D, 20, 30, 31, 33] # Example 1: 2nd to 1st place (ok: 10 < ? < 20)
[10, D, D, 30, 31, 33] # Example 2: 3rd to 1st place (ok: 10 < ? < ? < 30)
[10, D, 30, D, 31, 33] # Example 3: 3rd to 4th place (NOT OK: 30 < ? < 31)
[10, D, 30, D, D, 33] # must mark 5th as dirty too (ok: 30 < ? < ? < 33)
[10, D, D, 30, 31, 33] # Example 4: 3rd to 2nd place (ok)
id next
1 3
2 1
3
id next
1
2 1
3 2