基于每个列表的第一个值的自定义顺序的Python订单列表

时间:2018-02-07 11:12:45

标签: python python-3.x list sorting

我想根据每个列表的第一个值,按自定义顺序排列列表。列表列表是我的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')

3 个答案:

答案 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 tupletuple stringtuple tuple案例。

我们考虑了每一种情况,并为每种情况编写比较规则。

您在cmp语句中使用的return函数只是告知术语的关系,-1a < b0为{{ 1}}和a = b1

请注意,比较为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')]