To dość nubijne, ale staram się nauczyć / zrozumieć programowanie funkcjonalne w Pythonie. Poniższy kod:
foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3]
def maptest(foo, bar):
print foo, bar
map(maptest, foos, bars)
produkuje:
1.0 1
2.0 2
3.0 3
4.0 None
5.0 None
P: Czy istnieje sposób na użycie mapy lub innych narzędzi funkcjonalnych w Pythonie do tworzenia następujących elementów bez pętli itp.
1.0 [1,2,3]
2.0 [1,2,3]
3.0 [1,2,3]
4.0 [1,2,3]
5.0 [1,2,3]
Na marginesie, jak zmieniłaby się implementacja, gdyby istniała zależność między foo i bar. na przykład
foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3,4,5]
i wydrukuj:
1.0 [2,3,4,5]
2.0 [1,3,4,5]
3.0 [1,2,4,5]
...
PS: Wiem, jak to zrobić naiwnie, używając if, pętli i / lub generatorów, ale chciałbym się dowiedzieć, jak osiągnąć to samo za pomocą funkcjonalnych narzędzi. Czy jest to tylko przypadek dodania instrukcji if do maptest lub zastosowania innej mapy filtra do słupków wewnętrznie w maptest?
python
dictionary
functional-programming
eusoubrasileiro
źródło
źródło
Odpowiedzi:
Najłatwiej byłoby nie przechodzić
bars
przez różne funkcje, ale uzyskać do nich bezpośredni dostęp zmaptest
:foos = [1.0,2.0,3.0,4.0,5.0] bars = [1,2,3] def maptest(foo): print foo, bars map(maptest, foos)
W swojej oryginalnej
maptest
funkcji możesz również użyć funkcji lambda wmap
:map((lambda foo: maptest(foo, bars)), foos)
źródło
Czy znasz inne języki funkcjonalne? tj. czy próbujesz się nauczyć, jak Python działa w programowaniu funkcjonalnym, czy też próbujesz nauczyć się programowania funkcjonalnego i używać Pythona jako pojazdu?
Czy rozumiesz też listy ze zrozumieniem?
jest bezpośrednio równoważne (*) z:
[f(x) for x in sequence]
W rzeczywistości myślę, że
map()
kiedyś był przeznaczony do usunięcia z Pythona 3.0 jako zbędny (tak się nie stało).jest przeważnie równoważne z:
[f(x1, x2) for x1, x2 in zip(sequence1, sequence2)]
(istnieje różnica w sposobie postępowania w przypadku, gdy sekwencje mają różną długość. Jak widzieliście,
map()
wypełnia wartość None, gdy skończy się jedna z sekwencji, azip()
zatrzymuje się, gdy najkrótsza sekwencja się zatrzymuje)Tak więc, odpowiadając na swoje konkretne pytanie, próbujesz uzyskać wynik:
foos[0], bars foos[1], bars foos[2], bars # etc.
Możesz to zrobić, pisząc funkcję, która pobiera pojedynczy argument i wyświetla go, po którym następują paski:
def maptest(x): print x, bars map(maptest, foos)
Alternatywnie możesz utworzyć listę, która wygląda następująco:
[bars, bars, bars, ] # etc.
i użyj swojego oryginalnego testu map:
def maptest(x, y): print x, y
Jednym ze sposobów na zrobienie tego byłoby wyraźne utworzenie listy wcześniej:
Alternatywnie możesz pobrać
itertools
moduł.itertools
zawiera wiele sprytnych funkcji, które pomagają w programowaniu z leniwą oceną w stylu funkcjonalnym w Pythonie. W tym przypadku chcemyitertools.repeat
, aby jego argument był wyświetlany w nieskończoność podczas iteracji. Ten ostatni fakt oznacza, że jeśli:otrzymasz niekończące się dane wyjściowe, ponieważ
map()
trwa tak długo, jak długo jeden z argumentów nadal generuje wynik. Jednakitertools.imap
jest podobnymap()
, ale zatrzymuje się, gdy tylko najkrótsze iterowalne zatrzymania.Mam nadzieję że to pomoże :-)
(*) Trochę inaczej jest w Pythonie 3.0. Tam map () zasadniczo zwraca wyrażenie generatora.
źródło
itertools.imap(f, sequence1, sequence2)
naprawdę jest równoważne[f(x1, x2) for x1, x2 in zip(sequence1, sequence2)]
?list(itertools.imap(f, sequence1, sequence2))
Oto rozwiązanie, którego szukasz:
>>> foos = [1.0, 2.0, 3.0, 4.0, 5.0] >>> bars = [1, 2, 3] >>> [(x, bars) for x in foos] [(1.0, [1, 2, 3]), (2.0, [1, 2, 3]), (3.0, [1, 2, 3]), (4.0, [1, 2, 3]), (5.0, [ 1, 2, 3])]
Zalecałbym używanie list złożonych (
[(x, bars) for x in foos]
części) zamiast używania mapy, ponieważ pozwala to uniknąć narzutu wywołania funkcji przy każdej iteracji (co może być bardzo znaczące). Jeśli zamierzasz używać go tylko w pętli for, uzyskasz lepsze prędkości, używając funkcji rozumienia generatora:>>> y = ((x, bars) for x in foos) >>> for z in y: ... print z ... (1.0, [1, 2, 3]) (2.0, [1, 2, 3]) (3.0, [1, 2, 3]) (4.0, [1, 2, 3]) (5.0, [1, 2, 3])
Różnica polega na tym, że rozumienie generatora jest leniwie ładowane .
UPDATE W odpowiedzi na ten komentarz:
Przypuszczam, że to ważny punkt. Są dwa rozwiązania, które przychodzą mi do głowy. Najbardziej wydajne jest chyba coś takiego:
tbars = tuple(bars) [(x, tbars) for x in foos]
Ponieważ krotki są niezmienne, zapobiegnie to modyfikowaniu słupków w wyniku zrozumienia tej listy (lub zrozumienia przez generator, jeśli pójdziesz tą drogą). Jeśli naprawdę potrzebujesz zmodyfikować każdy z wyników, możesz to zrobić:
from copy import copy [(x, copy(bars)) for x in foos]
Jednak może to być trochę kosztowne zarówno pod względem zużycia pamięci, jak i szybkości, więc odradzam to, chyba że naprawdę musisz dodać do każdego z nich.
źródło
Programowanie funkcjonalne polega na tworzeniu kodu wolnego od efektów ubocznych.
mapa jest abstrakcją transformacji listy funkcjonalnej. Używasz go, aby wziąć sekwencję czegoś i przekształcić ją w sekwencję czegoś innego.
Próbujesz użyć go jako iteratora. Nie rób tego. :)
Oto przykład tego, jak możesz użyć mapy do zbudowania listy, którą chcesz. Istnieją krótsze rozwiązania (użyłbym tylko wyrażeń), ale to pomoże ci zrozumieć, która mapa działa trochę lepiej:
def my_transform_function(input): return [input, [1, 2, 3]] new_list = map(my_transform, input_list)
Zauważ, że w tym momencie dokonałeś tylko manipulacji danymi. Teraz możesz go wydrukować:
for n,l in new_list: print n, ll
- Nie jestem pewien, co masz na myśli mówiąc „bez pętli”. fp nie polega na unikaniu pętli (nie możesz sprawdzić każdej pozycji na liście bez odwiedzenia każdej z nich). Chodzi o unikanie efektów ubocznych, a tym samym pisanie mniej błędów.
źródło
>>> from itertools import repeat >>> for foo, bars in zip(foos, repeat(bars)): ... print foo, bars ... 1.0 [1, 2, 3] 2.0 [1, 2, 3] 3.0 [1, 2, 3] 4.0 [1, 2, 3] 5.0 [1, 2, 3]
źródło
import itertools foos=[1.0, 2.0, 3.0, 4.0, 5.0] bars=[1, 2, 3] print zip(foos, itertools.cycle([bars]))
źródło
Oto przegląd parametrów
map(function, *sequences)
funkcji:function
to nazwa twojej funkcji.sequences
to dowolna liczba sekwencji, które zwykle są listami lub krotkami.map
będzie iterował po nich jednocześnie i poda bieżące wartościfunction
. Dlatego liczba sekwencji powinna być równa liczbie parametrów twojej funkcji.Wygląda na to, że próbujesz wykonać iterację dla niektórych
function
parametrów, ale inne zachowujesz niezmienione, i niestetymap
tego nie obsługuje. Znalazłem starą propozycję dodania takiej funkcji do Pythona, ale konstrukcja mapy jest tak czysta i dobrze ugruntowana, że wątpię, aby coś takiego kiedykolwiek zostało zaimplementowane.Zastosuj obejście, takie jak zmienne globalne lub listy składane, zgodnie z sugestiami innych osób.
źródło
Czy to by to zrobiło?
foos = [1.0,2.0,3.0,4.0,5.0] bars = [1,2,3] def maptest2(bar): print bar def maptest(foo): print foo map(maptest2, bars) map(maptest, foos)
źródło
bar
oznacza, że otrzymuje iterowaną wartość, gdy w rzeczywistości chcesz mieć całą listę.Co powiesz na to:
foos = [1.0,2.0,3.0,4.0,5.0] bars = [1,2,3] def maptest(foo, bar): print foo, bar map(maptest, foos, [bars]*len(foos))
źródło