计算数组python

时间:2018-06-28 23:32:44

标签: python performance list-comprehension

我有一个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使用列表理解来使其更快?

4 个答案:

答案 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)