我想对从数据库查询返回的列进行排序.
在结果中,我想按以下顺序排序:
>关键字段,按查询结果中的位置排序(因为这通常反映了后端的唯一索引).
>其余键按字母顺序排列,因为该位置反映了表格的物理字段顺序,这无关紧要.
注意:这不是我想要在数据库级别执行的操作,这是一个Python排序问题.
我可以在Python 2.7中执行以下操作(请参见下面的代码),但是想为Python 3做准备.
过去,我已经编写了基于新型operator.attrgetter / itemgetter的排序,包括连续遍历,在此过程中,您首先按一个键函数进行排序,然后再按另一个.但是我看不到3的键功能系统将如何处理分支.
#test data, mangled on purpose
data = [
dict(fieldname="anotherkey2", pos=1, key=True),
dict(fieldname="somekey1", pos=0, key=True),
dict(fieldname="bfield3", pos=2, key=False),
dict(fieldname="afield", pos=3, key=False),
dict(fieldname="cfield", pos=4, key=False),
]
#exp keys, first, by position, then non-keys, alphabetic order
exp = ["somekey1","anotherkey2","afield","bfield3","cfield"]
def cmp2(field1, field2):
key1, key2 = field1.get("key"), field2.get("key")
#if both are keys, go by position in cursor results
if key1 and key2:
return cmp(field1["pos"], field2["pos"])
#if neither are keys, order alphabetically
if not (key1 or key2):
return cmp(field1["fieldname"], field2["fieldname"])
#otherwise, keys go first
return cmp(key2, key1)
for func in [cmp2]:
test_data = data[:]
test_data.sort(cmp=func)
got = [field["fieldname"] for field in test_data]
try:
msg = "fail with function:%s exp:%s:<>:%s:got" % (func.__name__, exp, got)
assert exp == got, msg
print ("success with %s: %s" % (func.__name__, got))
except AssertionError,e:
print(e)
输出:
success with cmp2: ['somekey1', 'anotherkey2', 'afield', 'bfield3', 'cfield']
此外,Sorting HOWTO中的cmp_to_key配方看起来很吓人,而且没有Python风格,每个魔术函数都有很多重复的代码.我不确定functools.cmp_to_key的相关性.
我想我能做的是用额外的属性预定义字段字典,该属性定义了排序方式.类似于sortby =(不是key,如果为key,则为pos,否则为0,字段名)元组,但是希望有一种更简洁的方法.
这行得通,但是….更好吗?
def pre_compute(data):
for row in data:
key, pos, fieldname = row["key"], row["pos"], row["fieldname"]
sortby = (not key, (pos if key else 0), fieldname)
row["sortby"] = sortby
for func in [pre_compute]:
test_data = data[:]
func(test_data)
test_data.sort(key=itemgetter('sortby'))
got = [field["fieldname"] for field in test_data]
try:
msg = "fail with function:%s exp:%s:<>:%s:got" % (func.__name__, exp, got)
assert exp == got, msg
print ("success with %s: %s" % (func.__name__, got))
except AssertionError,e:
print(e)
解决方法:
cmp_to_key()(独立版本或内置在functools模块中的版本)将可以与sort的cmp =参数一起使用的任意函数转换为与较新的key =参数一起使用的函数.这将是解决问题的最直接的解决方案(尽管某些评论者指出,让数据库为您完成可能会更好).