我有一个string
数组,例如[a_text, b_text, ab_text, a_text]
。我想获取包含每个前缀(例如['a_', 'b_', 'ab_']
)的对象的数量,因此'a_'
对象的数量将为2。
到目前为止,我一直在通过过滤数组来计数每个数组,例如num_a = len(filter(lambda x: x.startswith('a_'), array))
。我不确定这是否比遍历所有字段并递增每个计数器慢,因为我正在过滤要计数的每个前缀的数组。 filter()
之类的函数是否比for循环快?对于这种情况,如果使用for循环,则不需要构建过滤列表,这样可以使其更快。
也许还可以代替列表filter
使用列表理解来使其更快?
答案 0 :(得分:4)
您可以将 collections.Counter
与正则表达式配合使用(如果所有字符串都带有前缀):
from collections import Counter
arr = ['a_text', 'b_text', 'ab_text', 'a_text']
Counter([re.match(r'^.*?_', i).group() for i in arr])
输出:
Counter({'a_': 2, 'b_': 1, 'ab_': 1})
如果不是所有的字符串都有前缀,这将引发错误,因为re.match
将返回None。如果可能的话,只需增加一个步骤:
arr = ['a_text', 'b_text', 'ab_text', 'a_text', 'test']
matches = [re.match(r'^.*?_', i) for i in arr]
Counter([i.group() for i in matches if i])
输出:
Counter({'a_': 2, 'b_': 1, 'ab_': 1})
答案 1 :(得分:2)
另一种方法是使用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的答案相似,因为所有前缀都是一次计算的。但是,调用正则表达式方法似乎比简单的字符串操作要慢一些。但是我也必须回应迈克尔的评论,因为即使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
答案 2 :(得分:0)
如果我了解您的要求,似乎您真的想使用正则表达式(Regex)。它们是专门为这种模式匹配而设计的。我不了解Python,但是我确实看到支持正则表达式,因此使用它们就可以了。我使用this tool是因为它使制作和测试正则表达式变得容易。
答案 3 :(得分:0)
您还可以尝试使用str.partition()
来提取分隔符和分隔符之前的字符串,然后将这两个连接起来以形成前缀。然后,您只需要检查前缀集中是否存在该前缀,并用collections.Counter()
进行计数即可:
.index()
哪些输出:
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)