例如[a_text, b_text, ab_text, a_text]
,我有一个string
数组。我想要获取包含每个前缀的对象的数量,比如['a_', 'b_', 'ab_']
,这样'a_'
对象的数量就是2。
到目前为止,我一直在通过过滤数组来计算每个数组的值,例如num_a = len(filter(lambda x: x.startswith('a_'), array))
。我不确定这是否比循环遍历所有字段并递增每个计数器更慢,因为我是在为每个要计数的前缀过滤数组。像filter()
这样的函数比for循环快吗?对于这个场景,如果我使用For循环,我不需要构建过滤列表,这样可能会更快。
另外,也许我可以使用列表理解来代替filter
,以使其更快?
发布于 2018-06-29 08:08:36
另一种方法是使用defaultdict()
对象。您只需遍历整个列表一次,并在遇到时通过在下划线处拆分来计算每个前缀。您需要检查下划线是否存在,否则整个单词将被视为前缀(否则将无法区分'a'
和'a_a'
)。
from collections import defaultdict
array = ['a_text', 'b_text', 'ab_text', 'a_text'] * 250000
def count_prefixes(arr):
counts = defaultdict(int)
for item in arr:
if '_' in item:
counts[item.split('_')[0] + '_'] += 1
return counts
该逻辑类似于user3483203的答案,因为所有前缀都是在一次遍历中计算的。然而,调用正则表达式方法似乎比简单的字符串操作要慢一点。但我也不得不附和Michael的评论,因为即使是100万个项目,速度差异也是微不足道的。
from timeit import timeit
setup = """
from collections import Counter, defaultdict
import re
array = ['a_text', 'b_text', 'ab_text', 'a_text']
def with_defaultdict(arr):
counts = defaultdict(int)
for item in arr:
if '_' in item:
counts[item.split('_')[0] + '_'] += 1
return counts
def with_counter(arr):
matches = [re.match(r'^.*?_', i) for i in arr]
return Counter([i.group() for i in matches if i])
"""
for method in ('with_defaultdict', 'with_counter'):
print(timeit('{}(array)'.format(method), setup=setup, number=1))
计时结果:
0.4836089063341265
1.3238173544676142
发布于 2018-06-29 07:39:24
如果我理解您的要求,您似乎真的想使用正则表达式(Regex)。它们就是为这种模式匹配使用而构建的。我不知道Python,但我确实看到支持正则表达式,所以这是一个使用它们的问题。我使用this tool是因为它使得制作和测试您的正则表达式变得很容易。
发布于 2018-06-29 08:47:35
您还可以尝试使用str.partition()
提取分隔符和分隔符之前的字符串,然后将这两个字符串连接起来形成前缀。然后,您只需检查此前缀是否存在于前缀集中,并使用collections.Counter()
对其进行计数
from collections import Counter
arr = ['a_text', 'b_text', 'ab_text', 'a_text']
prefixes = {'a_', 'b_', 'ab_'}
counter = Counter()
for word in arr:
before, delim, _ = word.partition('_')
prefix = before + delim
if prefix in prefixes:
counter[prefix] += 1
print(counter)
以下哪项输出:
Counter({'a_': 2, 'b_': 1, 'ab_': 1})
https://stackoverflow.com/questions/51092428
复制相似问题