簡體   English   中英

如何使用索引搜索PYTHON加快嵌套for循環

[英]How to speed up a nested for loop with index search PYTHON

我從訂單簿獲取值,像這樣的列表:

list1 = [...,'ethbtc', '0.077666', '10', '0.077680', '15',...]
------------------------ ^符號----- ^值----- ^數量-

此列表中大約有100個符號,每個符號40個值。 它們始終處於相同順序。
我想知道如果我支付我說的余額的100%,此時系統可以購買的最高價是多少。

因此,如果我想以0.077666的價格購買11 ETH,那么實際價格將是0.077680,因為第一價格只有10 ETH可用。
我不想獲得平均值,因為此刻目前為止

我的代碼有一個嵌套的for循環,並通過2個列表循環:

  1. coinlist =其中列出了所有100個符號,例如: symbollist = [ethbtc, eoseth,...]
  2. 索引列表稱為a因為值和數量始終在同一位置
    a = ['1', '3', '5', ...]

我的代碼:

for symbolnow in symbollist:
sumlist = []
    for i in a:
        quantity = float(list1[list1.index(symbolnow) + (i+1)] if symbolnow in list1 else 0)
        sumlist.append(quantity)
        if sum(sumlist) > mycurrentbalance:
            maxvalue = float(list1[list1.index(symbolnow) + i] if symbolnow in list1 else -1)
            break
        else:
            maxvalue = -1

那么這段代碼是做什么的:
1)遍歷符號列表中的每個符號
2)對於找到的每個符號,我都會尋找可用的數量
3)如果我的余額(即10 ETH)小於數量,循環中斷
4)如果沒有,請繼續搜索和匯總匯總列表中的每個數量,直到足夠為止。

該代碼按預期工作,但速度不那么快。 不出所料list1.index需要很長時間才能執行。


更快的代碼將如何工作。 在這種情況下甚至是正則表達式中,列表理解是否更好? 我的代碼很丑嗎?

先感謝您!

編輯:
為了闡明輸入和所需的輸出,請提供一個樣本:

list1 = [...,'ethbtc', '0.077666', '1', '0.077680', '1.5', '0.077710', '3', '0.078200', '4',...]
mycurrentbalance = 5.5 <-余額以ETH為單位
list1中的每第三個條目都是以ETH為單位的數量,因此在列表中它將為['1', '1.5', '3', '4']

因此,如果我想賣出我所有的ETH(在這種情況下為5.5),最大值將為'0.077710'

list1包含100個符號,因此在'ethbtc'之前和之后還有其他值數量和符號

預處理list1並將其存儲在字典中。 這意味着您只需要遍歷list1一次,而不是每次您的內部循環運行一次。

price_dict = {'ethbtc': ['0.077666', '10', '0.077680', '15'], 'btceth': [...], ...}

而不是遍歷a ,而是遍歷range (Python 3)或xrange (Python 2)。 這將使用迭代器而不是列表,並使您的代碼更靈活。

range(0, len(price_dict[symbol]), 2)

在您的情況下,我認為如果有固定的間隔,使用slice對象將有助於您的'a'循環。 您可以將列表切片保存到對象,如下所示(還有1或2個其他技巧)。 我上面的用戶同意,如果您有機會對輸入數據進行預處理,那么您確實必須這樣做。 我建議為此使用pandas庫,因為它非常快,但是字典也將允許對值進行哈希處理。

input_data = ['ethbtc', '0.0776666', '10', '0.077680', '15']  # Give your variables meaningful names

length = 20 # a variable to store how long a list of values is for a particular symbol.

for symbol in symbollist: # Use meaningful names if loops too
    start = input_data.index(symbol)  # break up longer lines
    # Some exception handling here
    indxs = slice(start: start+length:2) # python lets you create slice objects
    quantities = [float(number) for number in input_data[indxs]]

    if sum(quantities) > mycurrentbalance:
        # Whatever code here
        ....

除了user3080953的答案之外,您還必須預處理數據,不僅因為這將更加高效,而且還可以幫助您處理復雜性。 在這里,您同時要做兩件事:解碼列表和使用數據。 首先解碼,然后使用。

我認為目標格式應為:

prices_and_quantities_by_symbol = {
    'ethbtc': {
        'prices':[0.077666, 0.077680, 0.077710, 0.078200], 
        'quantities':[1, 1.5, 3, 4]
    }, 
    'btceth': {
        ...
    }, 
...}

現在,您只需要執行以下操作:

for symbol, prices_and_quantities in prices_and_quantities_by_symbol.items(): # O(len(symbol_list))
    total = 0
    for p, q in zip(prices_and_quantities["prices"], prices_and_quantities["quantities"]): # O(len(quantities))
        total += q # the running sum
        if total >= my_current_balance:
            yield symbol, p # this will yield the symbol and the associated max_value
            break

如何獲取目標格式的數據? 只需遍歷列表,如果找到符號,就開始存儲值和數量,直到下一個符號為止:

prices_and_quantities_by_symbol = {}
symbol_set = (symbol_list) # O(len(symbol_list))
for i, v in enumerate(list1): # O(len(list1))
    if v in symbol_set:  # amortized O(1) lookup
        current_prices = []
        current_quantities = []
        current_start = i+1
        prices_and_quantities_by_symbol[v] = {
            'prices':current_prices, 
            'quantities':current_quantities
        }
    else: # a value or a quantity
        (current_prices if (i-current_start)%2==0 else current_quantities).append(float(v))

您進行了輕微但有趣的優化,尤其是在數量/值列表較長的情況下。 不存儲數量,但存儲數量的總計:

prices_and_running_total_by_symbol = {
    'ethbtc': {
        'prices':[0.077666, 0.077680, 0.077710, 0.078200], 
        'running_total':[1, 2.5, 5.5, 9.5]
    }, 
    'btceth': {
        ...
    }, 
...}

現在,您可以使用bisect快速找到您的max_value。 代碼變得更容易理解,因為bisect.bisect_left(rts, my_current_balance)將返回第一個運行總計>= my_current_balance

for symbol, prices_and_running_totals in prices_and_running_totals_by_symbol.items(): # O(len(symbol_list))
    ps = prices_and_running_totals["prices"]
    rts = prices_and_running_totals["running_total"]
    i = bisect.bisect_left(rts, my_current_balance) # O(log(len(rts)))
    yield symbol, ps[i] # this will yield the symbol and the associated max_value

要建立運行總計,您必須以不同的方式處理價格和數量:

# O(len(list1))
...
if v in symbol_set:  # amortized O(1) lookup*
    ...
elif (i-current_start)%2==0:
    current_prices.append(float(v))
else:
    current_running_totals.append((current_running_totals[-1] if current_running_totals else 0.0) + float(v))

將所有內容放入函數(或更好的類的方法)中:

prices_and_running_totals_by_symbol = process_data(list1)
for symbol, max_value in symbols_max_values(prices_and_running_totals_by_symbol, my_current_balance):
    print(symbol, max_value)

通過將問題分為兩個部分(解碼和使用),您可以看到代碼變得更快,並且(我認為)更易於理解(我沒有發表評論,但應該在那里)。

暫無
暫無

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

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