在字符串中比较前几个字符

3

所以我有一个字符串列表:

list1 = ["1thing", "2thing", "3thing", "1thing"]

我想了解列表中每个元素出现的次数。问题是,我只想比较前几个字符,因为我知道如果前面3个字符相同,那么整个字符串就相同。我在考虑修改内置的list.count(x)方法,或者覆盖__eq__运算符,但我不知道该如何实现。


4
我只想比较前几个字符,因为我知道如果前三个字符相同,那么整个字符串就是相同的。这种假设听起来可能会在未来出现问题。为什么不避免风险并检查整个字符串呢?从额外的复杂性和风险中你能获得什么好处呢? - Mark Byers
为什么要费力地尝试进行检查,而不使用内置的collections.Counter模块呢? - cobie
我这样做是因为实际上我正在检查一个包含100,000多个字符串的列表,每个字符串大约有80个字符,检查前25个字符可能比全部检查更快。我不知道这是否正确,但我正在尝试测试它。 - ohblahitsme
1
你有做过任何基准测试来证明使用 collections.Counter 不够快吗?关键是“不够快”。如果足够快,为什么要经历优化的压力呢?人们说要注意过早的优化。 - cobie
1
比较字符串的内置函数是C代码。如果您编写自定义Python代码,那么Python代码会减慢速度,以至于仅运行C代码会更快吗?我不知道,但如果您进行测量,您就会知道。我必须说,100,000个字符串并不算太多,因此即使特殊处理它们更快,您也不太可能节省很多时间。我刚刚进行了一个快速测试:我生成了100,000个长度为80的随机字符串,然后对它们进行了计数。使用默认字符串比较而不进行任何特殊技巧,计算所有字符串只需不到一秒钟的时间。 - steveha
3个回答

9

使用生成器提取前几个字符,并在其上使用内置的 collections.Counter 类:

Counter(item[:2] for item in list1)

5

为什么要费劲地去做,可以使用collections.Counter模块来查找频率。

>>> import collections
>>> x=['1thing', '2thing', '1thing', '3thing']
>>> y=collections.Counter(x)
>>> y
Counter({'1thing': 2, '2thing': 1, '3thing': 1})

1

这可能不如@Marcin的解决方案好,但使用itertools.groupby可以使其更易读和灵活。

from itertools import groupby

def group_by_startswith(it, n):
    """Get a dict mapping the first n characters to the number of matches."""

    def first_n(str_):
        return str_[:n]

    startswith_sorted = sorted(it, key=first_n)
    groups = groupby(startswith_sorted, key=first_n)

    return {key: len(list(grouped)) for key, grouped in groups}

例子输出:

>>> list1 = ["1thing", "2thing", "3thing", "1thing"]
>>> print(group_by_startswith(list1, 3))
{'3th': 1, '2th': 1, '1th': 2}

这个方案使结果具有更多的灵活性。例如,修改返回行以返回groupedlist(grouped),可以轻松获取匹配的对象。


为什么不能在生成器表达式的第一个元素中使用任意键函数? - Marcin
我想我应该再编辑一下。我试图在使用更多的函数式工具(如map)时,对将函数映射到一系列值上进行一些不必要的强调(在我看来,当您有一个更复杂的映射函数时,这样做更好)。 - Casey Kuball
生成器表达式只是映射的一种语法。这更多地是因材施教,除非您需要优化热点。 - Marcin

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