【问题标题】:Lazy sorted function, timsort惰性排序函数,timsort
【发布时间】:2019-04-19 11:21:17
【问题描述】:

有一个包含 N 个(大量)元素的列表:

from random import randint

eles = [randint(0, 10) for i in range(3000000)]

我正在尝试在下面实现此功能的最佳方式(性能/资源花费):

def mosty(lst):
    sort = sorted((v, k) for k, v in enumerate(lst))
    count, maxi, last_ele, idxs = 0, 0, None, []
    for ele, idx in sort:
        if(last_ele != ele):
            count = 1
            idxs = []
        idxs.append(idx)
        if(last_ele == ele):
            count += 1
            if(maxi < count):
                results = (ele, count, idxs)
                maxi = count
        last_ele = ele
    return results

此函数返回最常见的元素、出现次数以及找到它的索引。

这里是benchmark 300000 eles。

但我认为我可以改进,原因之一是 python3 sorted 函数 (timsort),如果它返回一个生成器,我不必循环遍历列表两次,对吧?

我的问题是:

有什么办法可以优化这段代码吗?怎么样?
我肯定会使用惰性排序,对吗?如何实现惰性 timsort

【问题讨论】:

  • 试试这个地方是否可以使用生成器。
  • 该函数到底想做什么?
  • 你当然可以改进你的实现,但我认为惰性排序的想法不是这样做的正确方法

标签: python python-3.x performance sorting


【解决方案1】:

没有做任何基准测试,但这不应该表现得那么糟糕(即使它在列表上迭代了两次):

from collections import Counter
from random import randint

eles = [randint(0, 10) for i in range(30)]

counter = Counter(eles)
most_common_element, number_of_occurrences = counter.most_common(1)[0]
indices = [i for i, x in enumerate(eles) if x == most_common_element]

print(most_common_element, number_of_occurrences, indices)

并且可以在生成器表达式中懒惰地找到索引(第二次迭代):

indices = (i for i, x in enumerate(eles) if x == most_common_element)

如果您需要关注最常见的多个元素,这可能对您有用:

from collections import Counter
from itertools import groupby
from operator import itemgetter

eles = [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5]

counter = Counter(eles)
_key, group = next(groupby(counter.most_common(), key=itemgetter(1)))
most_common = dict(group)
indices = {key: [] for key in most_common}

for i, x in enumerate(eles):
   if x in indices:
        indices[x].append(i)

print(most_common)
print(indices)

你当然仍然可以像上面一样让indices变得懒惰。

【讨论】:

  • @Chris_Rands 还没有到那里……抱歉。现在更新了。
  • 您无法处理联合顶部元素,例如eles = [1,1,2,2]
  • 这是正确的。感谢您指出。不过,这很容易解决。只要我不确定 OP 是否对此变体感兴趣,就不会对此进行调查...
【解决方案2】:

如果你愿意使用 numpy,那么你可以这样做:

arr = np.array(eles)
values, counts = np.unique(arr, return_counts=True)
ind = np.argmax(counts)
most_common_elem, its_count = values[ind], counts[ind]
indices = np.where(arr == most_common_elem)

HTH。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-11
    • 1970-01-01
    • 2016-01-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多