Как быстро перебрать большой список? - PullRequest
2 голосов
/ 11 марта 2020

Я пытаюсь перебрать большой список. Я хочу метод, который может быстро повторить этот список. Но для итерации требуется много времени. Есть ли способ быстрой итерации или python не создан для этого. Мой фрагмент кода: -

for i in THREE_INDEX:
    if check_balanced(rc, pc):
        print('balanced')
    else:
        rc, pc = equation_suffix(rc, pc, i) 

Здесь THREE_INDEX имеет длину 117649. Перебор этого списка занимает много времени, есть ли способ ускорить его. Но для итерации

functions_suffix функций требуется около 4-5 минут:

def equation_suffix(rn, pn,  suffix_list):
    len_rn = len(rn)
    react_suffix = suffix_list[: len_rn]
    prod_suffix = suffix_list[len_rn:]
    for re in enumerate(rn):
        rn[re[0]] = add_suffix(re[1], react_suffix[re[0]])
    for pe in enumerate(pn):
        pn[pe[0]] = add_suffix(pe[1], prod_suffix[pe[0]])
    return rn, pn

check_balanced function:

def check_balanced(rl, pl):
    total_reactant = []
    total_product = []
    reactant_name = []
    product_name = []
    for reactant in rl:
        total_reactant.append(separate_num(separate_brackets(reactant)))
    for product in pl:
        total_product.append(separate_num(separate_brackets(product)))
    for react in total_reactant:
        for key in react:
            val = react.get(key)
            val_dict = {key: val}
            reactant_name.append(val_dict)
    for prod in total_product:
        for key in prod:
            val = prod.get(key)
            val_dict = {key: val}
            product_name.append(val_dict)

    reactant_name = flatten_dict(reactant_name)
    product_name = flatten_dict(product_name)

    for elem in enumerate(reactant_name):
        val_r = reactant_name.get(elem[1])
        val_p = product_name.get(elem[1])
        if val_r == val_p:
            if elem[0] == len(reactant_name) - 1:
                return True
        else:
            return False

Ответы [ 2 ]

2 голосов
/ 11 марта 2020

Я считаю, что причина, по которой «итерация» списка занимает много времени, связана с методами, которые вы вызываете внутри для l oop. Я выбрал методы только для проверки скорости итерации, похоже, что итерация по списку размером 117649 очень быстрая. Вот мой тестовый скрипт:

import time

start_time = time.time()
new_list = [(1, 2, 3) for i in range(117649)]
end_time = time.time()
print(f"Creating the list took: {end_time - start_time}s")

start_time = time.time()
for i in new_list:
    pass
end_time = time.time()
print(f"Iterating the list took: {end_time - start_time}s")

Вывод:

Creating the list took: 0.005337953567504883s
Iterating the list took: 0.0035648345947265625s

Редактировать: time () возвращает секунду.

0 голосов
/ 11 марта 2020

General for циклы не проблема, но их использование для построения (или перестройки) list s обычно медленнее, чем использование списочных представлений (или в некоторых случаях map / filter, хотя те являются продвинутыми инструментами, которые часто являются пессимизацией).

Таким образом, ваши функции могут быть значительно упрощены, и они быстрее загрузятся. Пример переписывает:

def equation_suffix(rn, pn, suffix_list):
    prod_suffix = suffix_list[len(rn):]
    # Change `rn =` to `rn[:] = ` if you must modify the caller's list as in your
    # original code, not just return the modified list (which would be fine in your original code)
    rn = [add_suffix(r, suffix) for r, suffix in zip(rn, suffix_list)]  # No need to slice suffix_list; zip'll stop when rn exhausted
    pn = [add_suffix(p, suffix) for p, suffix in zip(pn, prod_suffix)]
    return rn, pn

def check_balanced(rl, pl):
    # These can be generator expressions, since they're iterated once and thrown away anyway
    total_reactant = (separate_num(separate_brackets(reactant)) for reactant in rl)
    total_product = (separate_num(separate_brackets(product)) for product in pl)
    reactant_name = []
    product_name = []
    # Use .items() to avoid repeated lookups, and concat simple listcomps to reduce calls to append
    for react in total_reactant:
        reactant_name += [{key: val} for key, val in react.items()]
    for prod in total_product:
        product_name += [{key: val} for key, val in prod.items()]

    # These calls are suspicious, and may indicate optimizations to be had on prior lines
    reactant_name = flatten_dict(reactant_name)
    product_name = flatten_dict(product_name)

    for i, (elem, val_r) in enumerate(reactant_name.items()):
        if val_r == product_name.get(elem):
            if i == len(reactant_name) - 1:
                return True
        else:
            # I'm a little suspicious of returning False the first time a single
            # key's value doesn't match. Either it's wrong, or it indicates an
            # opportunity to write short-circuiting code that doesn't have
            # to fully construct reactant_name and product_name when much of the time
            # there will be an early mismatch
            return False

Также отмечу, что использование enumerate без распаковки результата приведет к ухудшению производительности и увеличению количества крипт c кода; в этом случае (и во многих других) enumerate не требуется, так как listcomps и genexprs могут достичь sh того же результата, не зная индекса, но когда это необходимо, всегда распаковывать, например, for i, elem in enumerate(...):, затем использовать i и elem по отдельности всегда будут работать быстрее, чем for packed in enumerate(...): и с использованием packed[0] и packed[1] (и если у вас будет больше полезных имен, чем i и elem, загрузка будет намного более удобной для чтения ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...