Эквивалент понимания списка с использованием карты и фильтра - PullRequest
4 голосов
/ 14 апреля 2019

Я хочу написать этот код, используя карту и / или функцию фильтра. Возвращает индексы предметов в списке при условии, что сумма достигает целевого значения

Я использовал списочное понимание для этого, но не вижу, как получить второй цикл 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]

Ответы [ 4 ]

5 голосов
/ 14 апреля 2019

Так как 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, если он является членом набора, что можно сделать с помощью метода __contains__ набора, и, наконец, отобразить отфильтрованную последовательность на num.index, чтобы вывести индекс каждый соответствующий элемент:

list(map(num.index, filter(set(map(tgt.__sub__, num)).__contains__, num)))

Возвращает:

[0, 1, 2, 4, 6, 7]
0 голосов
/ 15 апреля 2019

Повторный вызов num.index очень неэффективен.Каждый раз, когда вы находите номер, который удовлетворяет вашему условию, вызов index требует последовательного сканирования списка.

Вместо этого переверните цикл над индексами в списке.Сделайте сравнение, проиндексировав массив (произвольный доступ), который будет намного более эффективным.

Как уже отмечали другие, вы можете использовать itertools.product, но вместо продукта num с самим собой, сделайтесам продукт 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 при тех соответствующих индексах равны цели.Поскольку product возвращает пару индексов, и вас интересует только первое значение, map - результат filter с itemgetter(0) для получения первого элемента.

Более компактно в качестве понимания списка:

[i for i, j in product(range(len(num)), range(len(num))) if num[i] + num[j] == tgt]
0 голосов
/ 14 апреля 2019

Попробуй это! Вы можете использовать itertools.product, чтобы получить комбинации каждого из них. Затем отфильтруйте список комбинаций для предметов, сумма которых составляет tgt. Затем сопоставьте лямбду с этими результатами, чтобы получить индекс первого элемента в этих комбинациях.

list(map(lambda x: num.index(x[0]), (filter(lambda x: sum(x) == tgt, itertools.product(num, repeat=2)))))
0 голосов
/ 14 апреля 2019

Двойной цикл может быть закодирован как 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, так как у нас есть кортежи, нам нужно использовать только одно из значений, помните, что первое соответствует вложенному циклу x num.index(x[0])

...