Задать вопрос

Как оптимизировать (ускорить) код на 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 = ' ')
  • Вопрос задан
  • 956 просмотров
Подписаться 2 Простой 3 комментария
Решения вопроса 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. Да вообще-то, тут всё говнокод. Лучше убери всё.
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Похожие вопросы
23 дек. 2024, в 16:13
50000 руб./за проект
23 дек. 2024, в 15:25
5000 руб./за проект
23 дек. 2024, в 14:47
4500 руб./за проект