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你是对的,但这是另一种方法。事实上,在我的回答中,我添加了你的评论,但我有另一个人的其他评论(投反对票),因为我重复了你的评论,因此,我删除了你不喜欢的图片。