#python #python-3.x #list #list-comprehension #map-function
#python #python-3.x #Список #понимание списка #карта-функция
Вопрос:
Я хочу написать этот код, используя карту и / или функцию фильтра. Он возвращает индексы элементов в списке при условии, что сумма соответствует цели
Для этого я использовал понимание списка, но не вижу, как получить второй цикл for в функцию map / filter. Я не уверен в синтаксисе, который будет использоваться, если я определю свою собственную функцию для аргумента функции функции map / filter
num = [2,5,7,11,6,15,3,4]
tgt= 9
[num.index(x) for x in num for y in num if x y == tgt]
Результаты:
[0, 1, 2, 4, 6, 7]
Ответ №1:
Поскольку оба filter
и map
работают над отдельными элементами в последовательности, вам придется просматривать свою логику с точки зрения каждого элемента в списке, а не комбинации элементов, а это означает, что вам нужно перефразировать выражения, используемые в вашем понимании списка, как функции отдельных элементов. Поэтому вместо условия фильтра x y == tgt
полезно просматривать его как x == tgt - y
, где y
также должен быть элемент в num
списке, чтобы ваше понимание списка можно было переписать как:
[num.index(x) for x in num if x in {tgt - y for y in num}]
При таком эквивалентном понимании списка становится ясно, что для реализации условия фильтра потребуется создать набор путем сопоставления каждого элемента с num
его разницей с tgt
, что можно сделать с tgt.__sub__
помощью метода, и проверить каждый элемент x
num
, является ли он членом набора, что можно сделать с помощьюметод set __contains__
и, наконец, сопоставьте отфильтрованную последовательность с num.index
для вывода индекса каждого соответствующего элемента:
list(map(num.index, filter(set(map(tgt.__sub__, num)).__contains__, num)))
Это возвращает:
[0, 1, 2, 4, 6, 7]
Комментарии:
1. Используйте
set
вместоlist
здесьlist(map(tgt.__sub__, num))
для лучшего поиска2. @blhsing Можете ли вы объяснить внутреннюю работу вашего решения?
Ответ №2:
Попробуйте это! Вы можете использовать itertools.product
для получения комбинаций каждого из них. Затем отфильтруйте список комбинаций для элементов, сумма которых равна tgt
. Затем сопоставьте лямбда-выражение с этими результатами, чтобы получить индекс первого элемента в этих комбинациях.
list(map(lambda x: num.index(x[0]), (filter(lambda x: sum(x) == tgt, itertools.product(num, repeat=2)))))
Ответ №3:
Двойной цикл может быть кодом в виде itertools.product
:
>>> list(map(lambda x: num.index(x[0]), filter(lambda x: sum(x) == tgt, itertools.product(num, num))))
[0, 1, 2, 4, 6, 7]
Давайте разберем код:
filter(lambda x: sum(x) == tgt, itertools.product(num, num))
itertools.product
возвращает итератор кортежей с элементами в num, (x, y)
аналогичный используемому вами вложенному циклу.
мы фильтруем, какому из этих кортежей равно суммирование tgt
, использование sum
здесь является лучшим выбором, но обратите внимание, что это будет то же x[0] x[1]
самое, что и (помните, что мы даем кортежи, подобные (2, 2)
этой функции).
После того, как мы отфильтровали, мы применяем для каждого из тех кортежей, которые остаются функцией num.index
, поскольку у нас есть кортежи, нам нужно использовать только одно из значений, помните, что первое соответствует вложенному циклу for x
, следовательно num.index(x[0])
Комментарии:
1. Спасибо, можете ли вы объяснить внутреннюю работу. Почему вы используете функции сокращения, т.е.(sum() и product()) и num.index(x[0]) ?
Ответ №4:
Повторный вызов num.index
очень неэффективен. Каждый раз, когда вы находите число, удовлетворяющее вашему условию, вызов index
требует последовательного сканирования списка.
Вместо этого включите цикл по индексам в списке. Сделайте сравнение, индексируя массив (произвольный доступ), что будет намного эффективнее.
Как указывали другие, вы можете использовать itertools.product
, но вместо продукта num
с самим собой, сделайте self product of range(len(num))
.
Использование map
и filter
:
from operator import itemgetter
from itertools import product
res = map(
itemgetter(0),
filter(
lambda c: num[c[0]] num[c[1]] == tgt,
product(range(len(num)),range(len(num)))
)
)
print(list(res))
#[0, 1, 2, 4, 6, 7]
Внутренняя filter
функция фильтрует все пары чисел от 0 до длины num
минус один, для которых значения num
в соответствующих индексах равны целевому. Поскольку продукт возвращает пару индексов, и вас интересует только первое значение, map
результат filter
с itemgetter(0)
, чтобы получить первый элемент.
Более компактно, как понимание списка:
[i for i, j in product(range(len(num)), range(len(num))) if num[i] num[j] == tgt]