你能有一个进度条来对列表进行排序吗?

Zci*_*rus 7 python sorting list python-3.x

我有一个包含约 50k 个自定义数据类型元素的列表(后者对我的问题可能并不重要)我正在使用 python 内置list.sort()方法对列表进行排序。

myList: List[Foo] = ...
myList.sort(key=Foo.x)
Run Code Online (Sandbox Code Playgroud)

由于排序需要几分钟,我希望排序过程有一个进度条。我在网上没有找到任何解决方案。

这可能吗?我知道排序算法可能很复杂,并且可能根本无法测量排序进度。然而,对于我的用例来说,有一个“粗略”的测量就可以了,比如 25%、50%、75%……

fla*_*kes 14

鉴于 提供的接口sort,您没有太多选项来挂钩实际的排序算法。但是,如果 50K 个键很慢,则很可能是调用该key函数很慢,这是在实际排序之前计算的。

\n

来自文档

\n
\n

列表中每一项对应的键都会计算一次,然后用于整个排序过程。

\n
\n

因此,如果您计算该方法被调用的次数key,您就可以获得整个排序过程的粗略估计。为此,您可以为该key函数创建一个包装器来管理簿记:

\n
def progress_sort(data, *, key=lambda v: v, on_increment=None):\n    total = len(data)\n\n    if on_increment is None:\n        start = time.time()\n\n        def on_increment(c):\n            print(f"{time.time() - start}: {c/total * 100}%")\n\n    count = 0\n\n    def progress_key(val):\n        nonlocal count\n        if count % int(total / 10) == 0:\n            on_increment(count)\n        count += 1\n        return key(val)\n\n    data.sort(key=progress_key)\n    on_increment(total)\n
Run Code Online (Sandbox Code Playgroud)\n

带有一些虚拟数据和慢速关键方法的示例

\n
def slow_key(val):\n    time.sleep(1.0/500_000)\n    return val\n\ndata = [random.randint(-50_000, 50_000)/1.0 for i in range(50_000)]\nprogress_sort(data, key=slow_key)\n
Run Code Online (Sandbox Code Playgroud)\n
0.0: 0.0%\n0.5136210918426514: 10.0%\n1.0435900688171387: 20.0%\n1.6074442863464355: 30.0%\n2.156496524810791: 40.0%\n2.9734878540039062: 50.0%\n3.4794368743896484: 60.0%\n4.016523599624634: 70.0%\n4.558118104934692: 80.0%\n5.047779083251953: 90.0%\n5.545809030532837: 100.0%\n
Run Code Online (Sandbox Code Playgroud)\n

然后可以将此方法与您希望用于更新状态的任何类型的库结合起来。您可能希望进一步配置提供给所提供的挂钩的数据,但是原理保持不变。

\n

这是一个使用的示例tqdm

\n
def slow_key(val):\n    time.sleep(1.0/500_000)\n    return val\n\n\ndata = [random.randint(-50_000, 50_000)/1.0 for i in range(50_001)]\n\nwith tqdm(total=len(data), desc="sorting") as pbar:\n    progress_sort(data, key=slow_key, on_increment=lambda c: pbar.update(c - pbar.n))\n    pbar.set_description("Finished")\n
Run Code Online (Sandbox Code Playgroud)\n
sorting:  80%|\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x89  | 40000/50001 [00:05<00:01, 5802.30it/s]\n
Run Code Online (Sandbox Code Playgroud)\n
Finished: 100%|\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88| 50001/50001 [00:07<00:00, 6489.14it/s]\n
Run Code Online (Sandbox Code Playgroud)\n

  • @toppk 请注意,这就是 sort 已经在做的事情。预先计算密钥表对于 cpython 实现已经为您执行的操作来说有些多余!:) https://github.com/python/cpython/blob/5113ed7a2b92e8beabebe5fe2f6e856c52fbe1a0/Objects/listobject.c#L2300-L2309 (2认同)