Как оптимизировать (ускорить) код на python?

Добрый день!

Помогите оптимизировать (ускорить) программу, не меняя ее сути, например, изменяя отдельные ее части. Даже незначительному улучшению производительности буду очень рад. Спасибо!

n, m = int(input()), int(input())
a = [[int(i) for i in input().split()] for w in range(m)]
input()
b = [int(i) for i in input().split()]

def listmerge(lstlst):
    all=[]
    for lst in lstlst:
      all.extend(lst)
    return all

def local(a,n):
    loc, locUse = [],[]
    for w in a:
        if w != []:
            if w[0] not in locUse and w[1] not in locUse:
                loc.append(w)
                locUse.extend(w)
            else:
                for i in range(len(loc)):
                    if w[0] in locUse and w[1] in locUse:
                        if w[0] in loc[i] and w[1] in loc[i]: None
                        else:
                            for j in range(i, len(loc)):
                                if w[0] in loc[i] and w[1] in loc[j] or w[1] in loc[i] and w[0] in loc[j]:
                                    loc[i] = listmerge([loc[i],loc[j]])
                                    loc[j] = []    
                    elif w[0] in locUse and w[1] not in locUse or w[1] in locUse and w[0] not in locUse:
                            if w[0] in loc[i]:
                                loc[i] = listmerge([loc[i],[w[1]]])
                                locUse.append(w[1])
                            elif w[1] in loc[i]:
                                loc[i] = listmerge([loc[i],[w[0]]])
                                locUse.append(w[0])

        while [] in loc:
            loc.remove([])

    return len(loc)+n-len(locUse)
             
for w in b:
    a[w-1] = []
    print(local(a,n), end = ' ')
  • Вопрос задан
  • 946 просмотров
Решения вопроса 1
adugin
@adugin Куратор тега Python
Первая ошибка - не использовать внятные имена переменных, в итоге в коде и логике совершенно невозможно разобраться. Проще заново переписать. Во-вторых, никогда не занимайтесь поиском x in list - для этого есть set'ы. В-третьих, не используйте индексы для итерации по списку, именно для этого придумали enumerate(). Вот предварительный рефакторинг:
def user_input():
    # n, m = int(input()), int(input())
    n = 2
    m = 4
    # a = [[int(i) for i in 'input()'.split()] for w in range(m)]
    first = [[1, 2], [3, 4, 5], [6, 7], [8, 9, 10, 11]]
    # input()
    # b = [int(i) for i in input().split()]
    second = [2, 3]
    return first, second, n

def process(list_of_lists, n):
    # Можно ли использовать множества? А вместо вложенных списков - tuple или set.
    seen_lists, seen_numbers = [], []
    has_at_least_two_items = lambda lst: lst and len(lst) >= 2
    for sublist in filter(has_at_least_two_items, list_of_lists):
        number0, number1 = sublist[:2]
        numbers = {number0, number1}  # Для ускорения проверок <x in Y>
        # Ни одно из чисел не встречалось ранее
        if not numbers.issubset(seen_numbers):
            seen_lists.append(sublist)
            seen_numbers.extend(sublist)
            # Здесь бы вставить continue и уменьшить вложенность блока ниже, но зачистка seen_lists перед return мешает
        else:  # Обработка списка, напоминающая сортировку пузырьком
            # Почему перебор до конца списка, а не до seen_lists[:-1]? Поправил.
            for i, seen_list_i in enumerate(seen_lists[:-1]):  # Заметка: слайс возвращает КОПИЮ списка
                sl_i = set(seen_list_i)  # Для ускорения проверок <x in Y>
                common = len(numbers.intersection(seen_numbers))
                # Оба числа встречались раньше
                if common == 2:
                    if numbers.issubset(sl_i):
                        continue
                    # Что будет, когда i == j == len(seen_lists) - 1?
                    for j, seen_list_j in enumerate(seen_lists[i:], i):  # Заметка: слайс возвращает КОПИЮ списка
                        sl_j = set(seen_list_j)  # Для ускорения проверок <x in Y>
                        if (number0 in sl_i and number1 in sl_j) or (number1 in sl_i and number0 in sl_j):
                            seen_list_i.extend(seen_list_j)
                            seen_list_j.clear()
                # Раньше встречалось только одно число из двух
                elif common == 1:
                    # Дальше у одного числа приоритет перед другим;
                    # Нельзя ли сделать nx = numbers - sl_i? Но проверить, что nx - это одно число, а не {number1, n2}
                    if number0 in sl_i:
                        nx = number1
                    elif number1 in sl_i:
                        nx = number0
                    else:
                        continue
                    seen_list_i.append(nx)
                    seen_numbers.append(nx)
        # Эта зачистка точно на своём месте? Можно её сделать перед return? Или удалять пустые сразу (выше)?
        seen_lists = [sublist for sublist in seen_lists if sublist]
    # В чём смысл этого результата?
    return len(seen_lists) - len(seen_numbers) + n

def main(first, second, n):
    for value in second:
        first[value-1].clear()  # В чём смысл?
        print(process(first, n), end=' ')


if __name__ == '__main__':

    main(*user_input())
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@deliro
1. Используй array вместо списков там, где можно. Иногда выгодней использовать множества. Особенно если ожидаются частые if X in C
2. Используй генераторы вместо списков там, где возможно
3. Убери весь говнокод вроде:
if w != []:
def listmerge(lstlst):
    all=[]
    for lst in lstlst:
      all.extend(lst)
    return all

while [] in loc:
4. Да вообще-то, тут всё говнокод. Лучше убери всё.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы