Python 在列表中计算列表元素的个数

4

假设我有以下列表:

L=[ [0,1,1,1],[1,0,1,1],[1,1,0,1],[1,1,1,0] ]

我希望编写一段代码,可以接收像这样的列表,并告诉我每个单独列表中的“1”的数量是否等于某个数字x。因此,如果我输入code(L,3),返回值将是“True”,因为L中的每个列表都包含3个“1”。但是,如果我输入code(L,2),返回值将是“False”。由于我对编程完全陌生,请谅解我表述不够清晰。感谢您的任何帮助。
4个回答

7

要判断每个子列表中是否有3个1,

all( x.count(1) == 3 for x in L )

或者作为一个函数:

def count_function(lst,number,value=1):
    return all( x.count(value) == number for x in lst )

L=[ [0,1,1,1],[1,0,1,1],[1,1,0,1],[1,1,1,0] ]
print(count_function(L,3)) #True
print(count_function(L,4)) #False
print(count_function(L,1,value=0)) #True

1
+1 我也赞同,但是你认为按照 OP 的要求创建 count_function(lst, number, value=1) 函数是不是更好的想法呢? - Tadeck
@Tadeck -- 非常好的建议(我甚至没有想到在这里使用默认参数)。谢谢!已进行编辑。 - mgilson

1
如果L是你的基本列表,n是你在每个“子列表”中期望的1的数量,则检查如下:
map(sum, l) == [n] * len(l)

整个函数及其测试如下所示:
>>> def check(l, n):
    return map(sum, l) == [n] * len(l)

>>> L=[ [0,1,1,1],[1,0,1,1],[1,1,0,1],[1,1,1,0] ]
>>> check(L, 3)
True
>>> check(L, 2)
False

编辑:替代方案包括:

  • {{link1:map(lambda x: x.count(1), l) == [n] * len(l)}}
  • {{link2:set(i.count(1) for i in l) == {n}}}(在此答案中最有效的方法)

但我认为最干净的方法是另一个回答者提供的{{link3:方法}}:

all(i.count(1) == n for i in l)

这甚至相当容易理解。


@mgilson:不正确。对于 L = [[0,0,1,1],[1,1,1,1]],它会在 check(L, 2)check(L, 4) 中都返回 False。你介意证明一下吗? - Tadeck
@mgilson:证明在这里:http://ideone.com/QkO1j。我已经测试了您和其他人在此线程中提供的所有“L”,并且使用介于“1”和“4”之间的“n”。结果似乎在说一些与您不同的事情。您能给个例子吗? - Tadeck
你是对的(抱歉)。我撤回我之前(不正确)的陈述。我误解了你的解决方案中发生的事情。 - mgilson
有一件令人有点担忧的事情是输入列表:L = [[1,2],[1,1,1]]。对于这个实例,check(L,3) 仍然返回 True。值得一提的是,您假设列表最初只包含0和1。 - mgilson
@mgilson:正如我在其他答案下回复的那样,它是基于实际问题(只包含0和1的列表)。而且,你的答案更加灵活(超出了实际问题的要求,但这很好)。你想让我点赞你的答案还是怎么样?;) - Tadeck
显示剩余2条评论

1
假设您的列表仅包含1和0,您可以轻松地计算其中的1: sum(sl)。您可以获取子列表的唯一计数集并测试它们是否都有三个1,如下所示:

set( sum(sl) for sl in L ) == set([3])

虽然与使用all()方法相比有点晦涩,但这种方法也可以让您测试所有子列表是否具有相同数量的“1”,而无需指定数量:

len(set( sum(sl) for sl in L )) == 1

你甚至可以“断言”子列表必须具有相同数量的1,并在一次操作中发现该数字:

[n] = set( sum(sl) for sl in L )

这将每个子列表中的1的数量分配给n,但如果子列表不都具有相同的数量,则会引发ValueError


这很聪明,但它只适用于“二进制”子列表(如果我错了请纠正我)--我的意思是仅包含两个数字的列表,并且其中一个数字必须为0。但是,对于稍微更聪明的方法,加1。 - mgilson
例如,L = [[1,2], [1,0,1,1]] 将返回 True,因为每个子列表的总和仍然为3(但当然,这个列表违反了你事先声明的假设)。 - mgilson
@mgilson: 这就是你方案的优势。我相信Marcelo和我都是根据列表只能包含零和一这个假设来回答问题的。看起来我们是正确的,但是你的代码更加灵活。 - Tadeck
@Tadeck:同意,但这只是为了简单起见。如果假设是错误的,只需将sum(sl)更改为sl.count(1),其他所有内容仍然有效。 - Marcelo Cantos

0
def all_has(count, elem, lst)
    """ensure each iterable in lst has exactly `count` of `elem`"""
    return all(sub_list.count(elem) == count for sub_list in lst)

>>> L = [ [0,1,1,1],[1,0,1,1],[1,1,0,1],[1,1,1,0] ]
>>> all_has(3, 1, L)
True
>>> all_has(2, 0, L)
False

使用生成器表达式改写列表推导式后的代码return all(sub_list.count(elem) == count for sub_list in lst)更加简洁,而且由于all函数会在第一个False出现时停止迭代,因此可能会更快。当然,如果你真的想要提高性能,仍然需要使用基准测试来确定哪种方法更快。 - Peter Graham
我不知道。我的第一反应是应该是 all( (x.count(e) == c for l in lst) ),但是在 all 中括号是不需要的?每天都有新的学习。 - yurisich
1
在函数调用中,如果生成器是唯一的参数,则括号不是必需的,这是一个特殊情况。 - mgilson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接