我想根据每个列表的第一个值,按自定义顺序排列列表。列表列表是我的pivot_table数据框(cols = list(dfOverview.columns.values)
)的列,其中一些列本身就是一个列表。
最小工作示例(我希望以b
开头的列在c
之前移动):
cols = ['2016', '2017', '2018',
('a', '2016'),
('a', '2017'),
('a', '2018'),
('c', '2016'),
('c', '2017'),
('c', '2018'),
('b', '2016'),
('b', '2017')]
sortOrder = {'2016': 0, '2017': 1, '2018': 2, 'a': 3, 'b': 4, 'c': 5}
cols.sort(key=lambda val: sortOrder[val[0]])
这会返回一个错误,即使我尝试了很多google,但我找不到让这个工作的方法。 cols的理想结果:
['2016', '2017', '2018',
('a', '2016'),
('a', '2017'),
('a', '2018'),
('b', '2016'),
('b', '2017'),
('c', '2016'),
('c', '2017'),
('c', '2018')]
澄清一下我的问题的一些背景:我转动了一个pandas数据框,产生了一个新的数据框,其中列可以包含一个值列表(具有多列作为参数的数据透视表)。这使得订购变得困难,因此出现了上述问题。
我的数据帧是以下函数的结果:
dfPivot = df.pivot_table(index=['col1', 'col2'],
columns=['year','category'],
values='price')
答案 0 :(得分:1)
问题源于您使用key
的事实。这用于指定要比较的值。你有一个异类列表。您将最终比较不同类型的元素。我建议你看一下cpm
参数,它是一个比较两个元素的函数。这样,您可以更精确地使用排序规则。
如果我理解你的问题,你很可能想要这样:
def compare(a, b):
if isinstance(a, str) and isinstance(b, str):
return cmp(a, b)
elif isinstance(a, str) and isinstance(b, tuple):
return cmp(a, b[1])
elif isinstance(b, str) and isinstance(a, tuple):
return cmp(a[1], b)
elif isinstance(a, tuple) and isinstance(b, tuple):
return cmp(a[1], b[1])
else:
print "Impossible"
return 0
cols.sort(cmp=compare)
print cols
查看列表输入时有4种情况需要区分。 string string
案例,string tuple
,tuple string
和tuple tuple
案例。
我们考虑了每一种情况,并为每种情况编写比较规则。
您在cmp
语句中使用的return
函数只是告知术语的关系,-1
为a < b
,0
为{{ 1}}和a = b
为1
。
请注意,比较为a > b
(字符串比较)。您可能希望将字符串置于整数并进行比较。
结果如下:
lexicographic
如果您通过访问第一个元组替换访问元组的第二个元素(在您的情况下为年份),您将得到:
['2016', ('a', '2016'), ('c', '2016'), ('b', '2016'), '2017', ('a', '2017'), ('c', '2017'), ('b', '2017'), '2018', ('a', '2018'), ('c', '2018')]
您可以添加一个标志来决定比较应该使用的元组项目。
答案 1 :(得分:1)
这会奏效。它将sort key
设置为元组的第一个元素,否则设置为变量本身。
cols = ['2016', '2017', '2018',
('a', '2016'),
('a', '2017'),
('a', '2018'),
('c', '2016'),
('c', '2017'),
('c', '2018'),
('b', '2016'),
('b', '2017')]
sorted(cols, key=lambda k: k[0] if isinstance(k, tuple) else k)
# ['2016',
# '2017',
# '2018',
# ('a', '2016'),
# ('a', '2017'),
# ('a', '2018'),
# ('b', '2016'),
# ('b', '2017'),
# ('c', '2016'),
# ('c', '2017'),
# ('c', '2018')]
答案 2 :(得分:1)
这种方式有点hacky,但你的方法也很hacky:D
>>> sorted(cols, key=lambda val: sortOrder[val[0]] if type(val) == tuple else sortOrder[val])
['2016', '2017', '2018', ('a', '2016'), ('a', '2017'), ('a', '2018'), ('b', '2016'), ('b', '2017'), ('c', '2016'), ('c', '2017'), ('c', '2018')]