python - 如何按“国际象棋顺序”对数组或查询集进行排序?
问题描述
任务是按“国际象棋顺序”对查询集进行排序。IE:
class Item(models.Model):
CHOICES = [
(1, 1),
(2, 2),
(3, 3),
]
branch = models.PositiveSmallIntegerField(choices=CHOICES)
item1.branch == 1
item2.branch == 1
item3.branch == 2
item4.branch == 3
item5.branch == 3
的期望输出Item.objects.all()
将是:
[item1, item3, item4, item2, item5]
因此,结果查询集将以分支(1,2,3), (1,2,3), (1,2,3)
等方式进行排序。
解决方案
我从来没有听说过象棋排序,但从你的描述来看,它似乎是这样定义的。
具有最小元素 x min和最大元素 x max的列表l如果是 x min则按照国际象棋排序顺序,并递归地选择以最小化步长k ,该步长 k被定义为最小正整数,使得mod x max。
l[0]
l[j]
l[j-1] + k == l[j]
换句话说,就像您只被允许将项目放置在与它们在棋盘上的值相对应的列上。如果每个元素都尽可能早地放置在棋盘上,则认为该列表已排序。
这种排序的问题在于它不是本地的。这意味着相对于其邻居正确放置的每个项目并不意味着整个列表已正确排序。这很重要,因为它表明我们将无法使用sorted
精心设计的key
参数对列表进行排序。
虽然,我们可以编写一个类似于按国际象棋顺序排序的计数排序的算法。
代码
from collections import defaultdict, deque
from itertools import cycle
def chess_sort(lst, key=lambda x: x):
count = defaultdict(deque)
for x in lst:
count[key(x)].append(x)
order = sorted(count)
output = []
for x in cycle(order):
if len(output) == len(lst):
break
if count[x]:
output.append(count[x].popleft())
return output
例子
import random
lst = random.choices(range(5), k=15)
print('list:', lst)
print('sorted:', chess_sort(lst))
输出
list: [0, 1, 4, 2, 1, 2, 1, 3, 4, 3, 0, 0, 0, 3, 2]
sorted: [0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 0]
适用于您的问题
请注意我如何允许传递 a key
to chess_sort
?您可以像使用它一样按属性sorted
对项目进行排序。branch
chess_sort(Item.objects.all(), key=lambda x: x.branch)
推荐阅读
- r - 如何将三角形添加到 R 中的 ggplot2 颜色条以指示超出范围的值?
- javascript - 为什么此代码更改字符串但又恢复到原始状态
- odoo - 如何禁用其他用户的更改密码选项?
- typescript - Typescript assumes the property type to be T | Properties["key"] instead of just T
- c++ - 就地创建和填充数组
- antlr4 - 如何解析无法转换为解析器规则的长词法规则的标记?
- hybris - 基于从 FlexQuery 获得的 PK 导入 Hybris Impex
- python-3.x - Python,将字典转换为逗号分隔值
- model - 如何使用 OR-Tools for python 描述目标大于零
- autodesk-forge - 模型衍生 API 对象 ID 与 PropertyDatabase 对象 ID 不匹配