【问题标题】:Count the total number of non-unique items in a list计算列表中非唯一项的总数
【发布时间】:2020-03-17 23:10:48
【问题描述】:

我正在寻找最省时的方法来计算 Python 的大型列表(大约 100,000 项)中非唯一项的数量。

我目前的方法:

original_list = [1, 4, 6, 2, 2, 1, 5, 3, 2]

duplicates_list = []
for item in original_list:
    if original_list.count(item) > 1:
        duplicates_list.append(item)

duplicates_count = len(duplicates_list)

print(duplicates_count)

# Should give the following answer:
5

目前,大约 70-80K 项的大型列表需要 1-2 分钟来执行计算。我想知道我们是否可以尽可能减少计算所需的时间(可能是 3-10 秒)。

非常感谢所有帮助!

【问题讨论】:

  • len(original_list) - len(set(original_list))@TimeAndPlaces
  • @Todd 我需要计算具有重复项的所有副本。我相信您的解决方案还将删除每个具有重复项的 1 个副本。
  • @Todd 这不起作用。它计算的是过剩的数量,而不是该集合的人口。
  • 没错,它只会计算重复的数量,不包括原始项目。
  • @Todd 你不能+ 1吗?

标签: python list optimization duplicates


【解决方案1】:

Counter 对象应该更快,因为在您的版本中,您对列表中的每个项目都调用 count(),因此每个问题 100,000 次。这将在整个列表上执行一次 Count(),然后对 Counter 对象的迭代将只对每个唯一值进行一次。

original_list = [1, 4, 6, 2, 2, 1, 5, 3, 2]

from collections import Counter
count = Counter(original_list)

dupes = sum(v for k, v in count.items() if v > 1)

【讨论】:

    【解决方案2】:

    这利用了 Counter 类中对算术运算符的支持 - setCounter 都支持几个有用的操作:

    >>> li = [1, 4, 6, 2, 2, 1, 5, 3, 2]
    >>> s  = set(li)
    >>>
    >>> len(li) - len(s) + len(Counter(li) - Counter(s))
    5
    >>> 
    

    len(li) - len(set(li)) 给出重复项的数量,或者我们取出set 项后剩余的列表项数。

    获取与剩余列表中的项目相关的设置项目列表:

    >>> list((Counter(li) - Counter(set(li))))
    [1, 2]
    

    并在set 项全部删除后获取列表中剩余的重复项列表:

    >>> list((Counter(li) - Counter(set(li))).elements())
    [1, 2, 2]
    

    如果列表有减法运算,这就是我们从列表中减去 set 后得到的结果。

    建议的优化

    如果可能,使用这个 70-80K 项目列表的应用程序应该在填充列表时从一开始就递增地构建计数器。它可以在需要时拥有其列表、计数器或其他需要的结构,因此指标或其他类型的处理可以在以后的步骤中变得快捷。

    基准测试

    以下是每个算法处理 80K 随机数列表所需的时间,不分先后。

    >>> li     = [random.randint(0, 100) for _ in range(80 * 1000)]
    >>> n_iter = 1000
    >>>
    >>> timeit.timeit("s = set(li); "
    ...               "len(li) - len(s) + len(Counter(li) - Counter(s))", 
    ...               globals=globals(), number=n_iter)
    7.048838693
    >>> 
    >>> timeit.timeit("sum(v for k, v in Counter(li).items() if v > 1)", 
    ...               globals=globals(), number=n_iter)
    5.787936814
    >>>
    >>> timeit.timeit(original_posters_script, globals=globals(), number=n_iter)
    # Takes too much time to sit through. It's very slow. O(N^2)
    >>> 
    

    毫不奇怪,最快的算法是所选答案中的另一个计数器解决方案。

    【讨论】:

    • 感谢您的调查!那么,我将如何定义重复项的数量+具有重复项的项目?只是想找一个词来减少混乱
    • 好的,我明白了。也许这行得通:“我想要唯一的非重复项目的数量。” “非重复项”与“非重复项”之间存在细微差别。
    • 真棒@TimesAndPlaces
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-19
    • 1970-01-01
    • 1970-01-01
    • 2021-05-03
    • 1970-01-01
    相关资源
    最近更新 更多