Задача "сумма двух" и списковое включение

Пытался решить задачку "Сумма двух" с помощью спискового включения, однако столкнулся с ошибкой:

did you forget parentheses around the comprehension target?

Основной код:

nums = [3,2,4]
target = 6
for x in range(len(nums)):
    if target - nums[x] in nums[x+1:len(nums)]:
        print([x, nums.index(target - nums[x], x+1, len(nums))])
        break

Главное, на входе получить список из size>=2 элементов, также получить значение, которое должно получится при сложении двух чисел target. В коде указал пример входа.

В попытках создать списковое включение:

outputList = [x, nums.index(target - nums[x], x+1, len(nums)) for x in range(len(nums)) if target - nums[x] in nums[x+1:len(nums)] == True]
print(outputList)

Я, конечно, понимаю, что я могу нарушать стиль PEP8, однако ради обучения можно отойти от стиля написания кода.

Ожидаемый вывод индексов в виде списка:

[1,2]

Опирался на реализацию этой строки:

new_list = [x for x in range(1, 10) if x % 2 == 0 if x % 3 == 0]

Однако результат трансляции моего кода отрицательный и чего-то недостаёт, я не могу заметить этого.

UPD:

outputList = [[x, nums.index(target - nums[x], x+1, len(nums))] for x in range(len(nums)) if target - nums[x] in nums[x+1:len(nums)] == True]
print(outputList)

После добавления [], мы можем указывать несколько переменных, однако вывод становится пустым.


Ответы (3 шт):

Автор решения: DiHASTRO

Суммаризация комментариев:

Условие

target - nums[x] in nums[x+1:len(nums)] == True

Априори ложное, так как сначала проверяется равенство

nums[x+1:len(nums)] == True

А только затем

target - nums[x] in False  # False <=> nums[x+1:len(nums)] == True

Убрав это сравнение, и оставив лишь

outputList = [[x, nums.index(target - nums[x], x+1, len(nums))] for x in range(len(nums)) if target - nums[x] in nums[x+1:len(nums)]]

Получим желаемый результат

→ Ссылка
Автор решения: Stanislav Volodarskiy

Исходный код из вопроса, отформатированный так, чтобы была заметна проблема:

outputList = [
    x,
    nums.index(target - nums[x], x + 1, len(nums))
    for x in range(len(nums))
    if target - nums[x] in nums[x + 1:len(nums)] == True
]

Проблема в том, что компилятор выражение [A, B] разбирает как список из двух элементов. Второй элемент – выражение-генератор, а генераторы всегда должны быть в скобках.

Автор вопроса хотел другого: что бы было одно выражение генератор, создающее список из пар. Для этого пару надо забрать в скобки, круглые для кортежа, квадратные для списка. Какой вариант выбрать, дело вкуса:

outputList = [
    (x, nums.index(target - nums[x], x + 1, len(nums)))
    for x in range(len(nums))
    if target - nums[x] in nums[x + 1:len(nums)] == True
]
outputList = [
    [x, nums.index(target - nums[x], x + 1, len(nums))]
    for x in range(len(nums))
    if target - nums[x] in nums[x + 1:len(nums)] == True
]

Теперь код компилируется, но не работает: результат всегда пустой. Потому что условие target - nums[x] in nums[x + 1:len(nums)] == True вычисляется неожиданным для программиста способом.

Замечу что == True – почти всегда ошибка. Оно не нужно в большинстве случаев. Если написать target - nums[x] in nums[x + 1:len(nums)] всё будет работать как надо.

Вернёмся к A in B == C. Это Питон, и цепочки сравнений, а in и == – сравнения, в нём компилируются специальным образом, а именно A in B and B == C. В нашем случае второй операнд and всегда ложный, ложно и целиком выражение.

Специальная компиляция сделана что бы вы могли следовать математической нотации в неравенствах: A < B < C будет скомпилировано как A < B and B < C. Это удобно, но отличается от других языков и вводит в заблуждение когда вы пишите штуки вроде A in B == C. Ставьте скобки, чтобы компилятор вас понял: (A in B) == C. Но, повторюсь, == True тут не нужно совсем.

Такой вариант будет работать, но медленно:

outputList = [
    (x, nums.index(target - nums[x], x + 1, len(nums)))
    for x in range(len(nums))
    if target - nums[x] in nums[x + 1:len(nums)]
]

TODO: предложить быстрое решение на генераторах списков.

→ Ссылка
Автор решения: Fox Fox

Готовый скрипт для тестирования:

import os

print("-" * 50 + "\nСумма двух чисел в списке с заданным результатом:\n" + "-" * 50)

def two_sum(nums, target):
    # Создаем пустой словарь для хранения чисел и их индексов
    num_to_index = {}
    
    # Проходим по каждому числу в массиве
    for i, num in enumerate(nums):
        # Вычисляем дополнение, которое вместе с текущим числом даст в сумме target
        complement = target - num
        
        # Проверяем, есть ли дополнение в словаре
        if complement in num_to_index:
            # Если есть, возвращаем индексы текущего числа и дополнения
            indices = [num_to_index[complement], i]
            # Выводим сумму элементов результирующего списка
            print(f"Сумма элементов: {nums[indices[0]] + nums[indices[1]]}")
            return indices
        
        # Если дополнения нет, добавляем текущее число и его индекс в словарь
        num_to_index[num] = i
    
    # Если решение не найдено, возвращаем пустой список
    return []

# Пример использования
nums = [2, 7, 11, 15]
target = 9
print(two_sum(nums, target))  # Вывод: [0, 1]

print("\nНажмите любую клавишу для продолжения...")
os.system("pause > nul" if os.name == "nt" else "read > /dev/null")
→ Ссылка