簡體   English   中英

查找整數列表最大值的最快方法

[英]fastest way to find maximum of list of list of integers

假設我有a: list[list[int]] = [[1, 2, 3], [4, 5, 6], [1, 7, 1]]

max_a: int = max([max(tmp_list) for tmp_list in a])是最佳方式嗎? 還是有更快的方法?

我將處理大約 10 個元素的 8 個列表。 每次啟動算法時,我都會尋找大約 160,000 次的最大值。

我會使用 Pythons 標准庫中的itertools.chain.from_iterable

from itertools import chain
max_a = max(chain.from_iterable(a))
print(max_a)

至少在我的系統上,它比問題中的方法(用timeit測量)更快,但在不同版本的 Python 中可能會有所不同。 有趣的事實:如果我修改問題中的代碼以使用生成器表達式,它會更慢。

更多方法/基准:

2.30 us  2.30 us  2.31 us  chained
2.85 us  2.86 us  2.86 us  self
2.88 us  2.89 us  2.91 us  self2
2.99 us  3.00 us  3.03 us  mapmax
3.45 us  3.45 us  3.45 us  listcomp
3.46 us  3.54 us  3.54 us  genexp

代碼( 在線試用! ):

def listcomp(a):
    return max([max(tmp_list) for tmp_list in a])

def genexp(a):
    return max(max(tmp_list) for tmp_list in a)

def mapmax(a):
    return max(map(max, a))

def chained(a):
    return max(chain.from_iterable(a))

def self(a):
    maxi = -1
    for b in a:
        for c in b:
            if c > maxi:
                maxi = c
    return maxi

def self2(a):
    maxi = a[0][0]
    for b in a:
        for c in b:
            if c > maxi:
                maxi = c
    return maxi

funcs = [listcomp, genexp, mapmax, chained, self, self2]

from timeit import repeat
import random
from bisect import insort
from collections import deque
from itertools import chain

tests = 100
A = [[random.choices(range(1000), k=10) for _ in range(8)]
     for _ in range(tests)]

expect = list(map(funcs[0], A))
for func in funcs:
    result = list(map(func, A))
    assert result == expect, func.__name__

times = {func: [] for func in funcs}
for _ in range(10):
    random.shuffle(funcs)
    for func in funcs:
        time = min(repeat(lambda: deque(map(func, A), 0), number=1)) / tests
        insort(times[func], time)
for func in sorted(funcs, key=times.get):
    print(*('%.2f us ' % (t * 1e6) for t in times[func][:3]), func.__name__)

首先, 過早優化真的是萬惡之源嗎? 現在,關於優化的事情是它可以非常依賴輸入。 即使理論上某些方法更適合大輸入量,但啟動環境以運行它的成本可能超過使用更復雜方法所獲得的收益。 下面是我為測試不同算法而創建的示例代碼。

當使用您提供的數據大小運行時,似乎簡單的 double max 最適合這項工作,而使用 numpy 數組總是較慢。 我看到一些性能提升的可能性是 numba 的 JIT 與 np.array 相結合。 在您的樣本量下它會變慢,但是當問題增長時,它會變得越來越有效。 最重要的是,后續調用效率更高,因為它們已經編譯,比所有其他選項高出幾個數量級。

如您所見,如果您希望獲得實際的性能增益,則無法在空白中比較算法,並且應該在實際工作數據上逐案選擇和測試。

import random
import numpy as np
from numba import njit
from itertools import chain
n, m = 8, 10
ls = [[random.uniform(0, 1) for _ in range(n)] for _ in range(m)]

k = 160000
from functools import wraps
from time import time

def timing(f):
    @wraps(f)
    def wrap(*args, **kw):
        ts = time()
        result = f(*args, **kw)
        te = time()
        print(f"func:{f.__name__} took {te-ts}s, {result=}")
        return result
    return wrap

@timing
def test1(k, ls):
    for i in range(k):
        max(max(ls))
    return max(max(ls))

npls = np.array(ls)

@timing
def test2(k, npls):
    for i in range(k):
        npls.max()
    return npls.max()

@timing
@njit
def test3(k, npls):
    for i in range(k-1):
        npls.max()
    return npls.max()
    
@timing
def test4(k, ls):
    for i in range(k):
        max(chain.from_iterable(ls))
    return max(chain.from_iterable(ls))

test1(k, ls)
test2(k, npls)
test3(k, npls)
test4(k, ls)

ls = [[random.uniform(0, 1) for _ in range(n)] for _ in range(m)]
npls = np.array(ls)

test3(k, npls)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM