【发布时间】:2017-07-12 02:12:29
【问题描述】:
我想对从数据库查询返回的列进行排序以进行展示。 在结果中,我想按以下方式排序:
首先是键字段,按查询结果中的位置排序(因为这通常反映后端的唯一索引)。
其余键按字母顺序排列,因为位置反映了不感兴趣的表物理字段顺序。
注意:这不是我想在数据库级别做的事情,这是一个 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 = (not key, pos if key else 0, fieldname) 元组的东西,但希望有更简洁的方法。
这行得通,但是....还有什么更好的吗?
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)
【问题讨论】:
-
这不能在数据库级别完成吗?即查询本身中的orderby。
-
您编写的比较器可以使用元组键和条件表达式转换为键函数,但让数据库处理排序可能是更好的方法。
-
@DeepSpace。不,真的不能。这相当于生成或硬编码一个查询,其中的列为
select somekey1, anotherkey2, afield, bfield3, cfield,实际上超出了范围。这不是结果集的order by,而是要显示的列的顺序。此外,数据库方面仅供参考,核心问题是如何在 Python 3 中进行这种排序。
标签: python python-2.7 python-3.x sorting