Python中按出现次数排列的向量顺序列表
我试图按特定元素的出现次数对列表进行排序(逆序) 我试过使用后面的表达式:Python中按出现次数排列的向量顺序列表,python,list,sorting,Python,List,Sorting,我试图按特定元素的出现次数对列表进行排序(逆序) 我试过使用后面的表达式: a = [[0,1,0],[1,1,1], [0,1,1] a.sort(key = (a).count(1) , reverse = True) 所需输出必须为: a = [[1,1,1],[0,1,1],[0,1,0]] 但我得到了一个错误: TypeError: 'int' object is not callable 也许,我在扩展“键”的定义。有没有一种方法可以在不硬编码的情况下执行我上面尝试的操作,并以
a = [[0,1,0],[1,1,1], [0,1,1]
a.sort(key = (a).count(1) , reverse = True)
所需输出必须为:
a = [[1,1,1],[0,1,1],[0,1,0]]
但我得到了一个错误:
TypeError: 'int' object is not callable
也许,我在扩展“键”的定义。有没有一种方法可以在不硬编码的情况下执行我上面尝试的操作,并以更具python风格的方式执行?参数
key
接受可调用的对象,例如函数。您将调用函数的结果传递给参数,该参数将被计算为int
因此,您可以这样做:
def count_key(x): return x.count(1)
a = [[0,1,0],[1,1,1], [0,1,1]
a.sort(key=count_key, reverse = True)
您最初的尝试表明您正在寻找匿名函数。Python支持带有lambda
关键字的匿名函数,这是一个典型的用例:
a = [[0,1,0],[1,1,1], [0,1,1]
a.sort(key=lambda x: x.count(1), reverse = True)
编辑以添加一些测试
快速测试:
In [11]: %%timeit import functools; a = 10000*[100*[0,1,0],100*[1,1,1], 100*[0,1,1]]
...: a.sort(key = lambda x: x.count(1), reverse = True)
...:
10 loops, best of 3: 54.7 ms per loop
In [12]: %%timeit import functools; a = 10000*[100*[0,1,0],100*[1,1,1], 100*[0,1,1]]
...: a.sort(key = sum, reverse = True)
...:
10 loops, best of 3: 75.1 ms per loop
令人惊讶的是,lambda
似乎胜出了。但是,如果内部列表很小,sum
获胜:
In [16]: %%timeit import functools; a = 10000*[[0,1,0],[1,1,1], [0,1,1]]
...: a.sort(key = lambda x: x.count(1), reverse = True)
...:
100 loops, best of 3: 5.2 ms per loop
In [17]: %%timeit import functools; a = 10000*[[0,1,0],[1,1,1], [0,1,1]]
...: a.sort(key = sum, reverse = True)
...:
100 loops, best of 3: 3.82 ms per loop
现在,随着更大的内部列表,lambda
再次获得优势:
In [18]: %%timeit import functools; a = 10000*[1000*[0,1,0],1000*[1,1,1], 1000*[0,1,1]]
...: a.sort(key = lambda x: x.count(1), reverse = True)
...:
1 loop, best of 3: 482 ms per loop
In [19]: %%timeit import functools; a = 10000*[1000*[0,1,0],1000*[1,1,1], 1000*[0,1,1]]
...: a.sort(key = sum, reverse = True)
...:
1 loop, best of 3: 679 ms per loop
键
必须是函数,而不是表达式
您可以将任何表达式转换为与lambda
对齐的函数:
a.sort(key=lambda sublist: sublist.count(1), reverse=True)
通常更清楚的是,要么将功能放在一边:
def countones(lst):
return lst.count(1)
a.sort(key=countones, reverse=True)
…或使用(绑定或未绑定)方法、部分或高阶函数。大概是这样的:
a.sort(key=functools.partial(list.count, value=1), reverse=True)
…除了list.count
实际上是一个不接受关键字参数的内置项,所以您不能简单地编写它
在本例中,我认为
lambda
非常清楚。参数的工作原理是获取一个callable,并将其应用于列表中的每个元素,以确定它在最终排序结果中应该位于哪个位置
在您的情况下,传递a.count(1)
,在调用list.sort
之前对其进行评估。排序时,python将尝试调用传递的结果(在本例中为0
),但由于int
s不可调用而失败。如上所述,诀窍是传递一个callable
如果要传递内联可调用函数,则需要使用lambda
函数:
a.sort(key=lambda x: x.count(1), reverse=True)
否则,定义一个函数作为其他答案显示,并将其传递给list.sort
作为排序键
最后,如果列表只有0和1,可以使用key=sum
进行微优化
a.sort(key=sum, reverse=True)
在这种情况下(假设本例成立),
sum(x)
和x.count(1)
将返回相同的结果。最简单的方法是使用lambda函数:
>>> a.sort(key = lambda x: sum(x),reverse = True)
[[1, 1, 1], [0, 1, 1], [0, 1, 0]]
您也可以尝试:
a = [[0,1,0],[1,1,1], [0,1,1]]
print(sorted(a,key=lambda x:x.count(1),reverse=True))
输出:
[[1, 1, 1], [0, 1, 1], [0, 1, 0]]
(a).count(1)
立即调用list
上的count
方法,计算a
中出现1
的次数,并将该计数作为int
返回,该值将为0
。您需要为键
参数提供一个可调用的参数,例如lambda。现在明白了,谢谢所有回答我问题的人!这真的是一个微观优化吗?我希望sum
和count(1)
的速度大致相同,可能是sum
起步更快,但随着列表越来越大而落后。而且我不希望速度增益足以补偿脆性,也不太明显。@abarnert Microoptimization=no lambda。。。当然,它仍然是同样复杂的。是的,没有lambda意味着它几乎肯定会赢得大量的列表,但更多的工作意味着我不确定是否会有大量的列表。不管怎样,如果这有关系,你会想用你的真实数据来测试它,所以争论我们的猜测毫无意义@阿巴内特实际上正在尝试这样做。我认为partial不能用于list.count
,因为value实际上是一个位置参数。@juanpa.arrivillaga Oops,关于list.count
,您是对的;谢谢。@cᴏʟᴅsᴘᴇᴇᴅ 不会的,双百分比timeit ipython magic,%%timeit
将使第一行成为设置
,第二行是stmt
好的,还有一件事。你在python3.6上计时了吗?我不能准确地复制你的结果。我像你一样试了两个例子,a=np.random.randint(0,2,(10000,100)).tolist()
和a=np.random.randint(0,2,(100,10000)).tolist()
在这两个例子中,key=sum
都胜出,但胜算不大。另一个注意事项是,我用sorted
计时,而不是list。sort
key=sum
就足够了,lambda x:sum(x)
只做sum
@timgeb你是对的,但这是另一种方法。事实上,在我的回答中,我添加了你的评论,但我有另一个人的其他评论(投反对票),因为我重复了你的评论,因此,我删除了你不喜欢的图片。