【发布时间】:2011-08-15 05:57:15
【问题描述】:
我想获取 x 在嵌套列表中出现的次数。
如果列表是:
list = [1, 2, 1, 1, 4]
list.count(1)
>>3
没关系。但如果列表是:
list = [[1, 2, 3],[1, 1, 1]]
如何获取 1 出现的次数?在这种情况下,4.
【问题讨论】:
-
先展平。到处搜索。
我想获取 x 在嵌套列表中出现的次数。
如果列表是:
list = [1, 2, 1, 1, 4]
list.count(1)
>>3
没关系。但如果列表是:
list = [[1, 2, 3],[1, 1, 1]]
如何获取 1 出现的次数?在这种情况下,4.
【问题讨论】:
试试这个:
reduce(lambda x,y: x+y,list,[]).count(1)
基本上,您从一个空列表 [] 开始,然后将列表 list 的每个元素添加到其中。在这种情况下,元素本身就是列表,您会得到一个扁平列表。
PS:刚刚在另一个问题中的类似答案被否决了!
PPS:这个解决方案也被否决了!
【讨论】:
itertools 和 collections 模块得到了你需要的东西(使用 itertools.chain 展平嵌套列表并使用 collections.Counter 计数
import itertools, collections
data = [[1,2,3],[1,1,1]]
counter = collections.Counter(itertools.chain(*data))
print counter[1]
使用递归展平函数而不是itertools.chain 展平任意级别深度的嵌套列表
import operator, collections
def flatten(lst):
return reduce(operator.iadd, (flatten(i) if isinstance(i, collections.Sequence) else [i] for i in lst))
reduce 和 operator.iadd 已被使用而不是 sum,因此扁平化只构建一次并就地更新
【讨论】:
>>> L = [[1, 2, 3], [1, 1, 1]]
>>> sum(x.count(1) for x in L)
4
【讨论】:
如果只有一层嵌套扁平化可以用这个列表压缩来完成:
>>> L = [[1,2,3],[1,1,1]]
>>> [ item for sublist in L for item in sublist ].count(1)
4
>>>
【讨论】:
最重要的是:计数到任意嵌套深度,处理元组、列表和参数:
hits = lambda num, *n: ((1 if e == num else 0)
for a in n
for e in (hits(num, *a) if isinstance(a, (tuple, list)) else (a,)))
lst = [[[1,(1,),((1,(1,))), [1,[1,[1,[1]]]], 1, [1, [1, (1,)]]]]]
print sum(hits(1, lst, 1, 1, 1))
15
【讨论】:
lambda 施虐者 ;-)。这也回答了如何在自身中递归嵌入生成器的问题:-)。
def nested_count(lst, x):
return lst.count(x) + sum(
nested_count(l,x) for l in lst if isinstance(l,list))
此函数返回出现次数,加上所有包含的子列表中的递归嵌套计数。
>>> data = [[1,2,3],[1,1,[1,1]]]
>>> print nested_count(data, 1)
5
【讨论】:
这是另一种扁平化嵌套序列的方法。一旦序列被展平,就很容易找到项目的数量。
def flatten(seq, container=None):
if container is None:
container = []
for s in seq:
try:
iter(s) # check if it's iterable
except TypeError:
container.append(s)
else:
flatten(s, container)
return container
c = flatten([(1,2),(3,4),(5,[6,7,['a','b']]),['c','d',('e',['f','g','h'])]])
print(c)
print(c.count('g'))
d = flatten([[[1,(1,),((1,(1,))), [1,[1,[1,[1]]]], 1, [1, [1, (1,)]]]]])
print(d)
print(d.count(1))
以上代码打印:
[1, 2, 3, 4, 5, 6, 7, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
1
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
12
【讨论】:
'a' 这样的字符串实际上是可迭代的。这意味着它将继续调用递归。
iter的行为在版本之间发生了变化,或者我发布的代码是错误的我发布的那天,错误仍未被发现。
以下函数将通过向结果输出列表添加非列表并递归处理列表来展平任何深度的列表(a):
def flatten(listOrItem, result = None):
if result is None: result = [] # Ensure initial result empty.
if type(listOrItem) != type([]): # Handle non-list by appending.
result.append(listOrItem)
else:
for item in listOrItem: # Recursively handle each item in a list.
flatten(item, result)
return result # Return flattened container.
mylist = flatten([[1,2],[3,'a'],[5,[6,7,[8,9]]],[10,'a',[11,[12,13,14]]]])
print(f'Flat list is {mylist}, count of "a" is {mylist.count("a")}')
print(flatten(7))
一旦你有了一个扁平化的列表,使用count 就很简单了。
该代码的输出是:
Flat list is [1, 2, 3, 'a', 5, 6, 7, 8, 9, 10, 'a', 11, 12, 13, 14], count of "a" is 2
[7]
如果您不传递实际列表,请注意行为,它假定您无论如何都想要一个列表,一个仅包含单个项目的列表。
如果您不想要构造一个扁平列表,您可以使用类似的方法来获取列表列表中任何项目的计数,例如:
def deepCount(listOrItem, searchFor):
if type(listOrItem) != type([]): # Non-list, one only if equal.
return 1 if listOrItem == searchFor else 0
subCount = 0 # List, recursively collect each count.
for item in listOrItem:
subCount += deepCount(item, searchFor)
return subCount
deepList = [[1,2],[3,'a'],[5,[6,7,[8,9]]],[10,'a',[11,[12,13,14]]]]
print(f'Count of "a" is {deepCount(deepList, "a")}')
print(f'Count of 13 is {deepCount(deepList, 13)}')
print(f'Count of 99 is {deepCount(deepList, 99)}')
正如预期的那样,这个输出是:
Count of "a" is 2
Count of 13 is 1
Count of 99 is 0
(a) 当然,在 Python 本身施加的限制范围内,您可以通过将其添加到代码顶部来增加限制:
import sys
sys.setrecursionlimit(1001) # I believe default is 1000.
我提到,在 case 中,你有一些非常深刻的嵌套结构,但你不应该真的需要它。如果你嵌套得那么深,那么你可能做错了什么:-)
【讨论】: