파이썬 맵 및 기타 기능 도구 사용


127

이것은 꽤 n00bish이지만 파이썬에서 함수형 프로그래밍을 배우거나 이해하려고합니다. 다음 코드 :

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)

생산 :

1.0 1
2.0 2
3.0 3
4.0 None
5.0 None

Q. 파이썬에서 map 또는 기타 기능 도구를 사용하여 루프없이 다음을 생성하는 방법이 있습니까?

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]

사이드 노트와 마찬가지로 foo와 bar 사이에 종속성이 있으면 구현이 어떻게 변경됩니까? 예 :

foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3,4,5]

인쇄 :

1.0 [2,3,4,5]
2.0 [1,3,4,5]
3.0 [1,2,4,5]
...

추신 : 나는 if, 루프 및 / 또는 생성기를 사용하여 순진하게 수행하는 방법을 알고 있지만 기능적 도구를 사용하여 동일한 것을 달성하는 방법을 배우고 싶습니다. maptest에 if 문을 추가하거나 maptest 내부의 막대에 다른 필터 맵을 적용하는 경우입니까?


고마워 파이썬을 통해 함수형 프로그래밍의 개념을 배우려고 노력하고 있음을 인정해야합니다.

1
그것을위한 좋은 튜토리얼 : dreamsyssoft.com/python-scripting-tutorial/…
Rocky Pulley

답변:


54

가장 쉬운 방법은 bars다른 기능을 거치지 않고 다음에서 직접 액세스하는 것입니다 maptest.

foos = [1.0,2.0,3.0,4.0,5.0]
bars = [1,2,3]

def maptest(foo):
    print foo, bars

map(maptest, foos)

원래 maptest함수를 사용하면 다음에서 람다 함수를 사용할 수도 있습니다 map.

map((lambda foo: maptest(foo, bars)), foos)

바가 목록에서 올 때 나쁜 것
Phyo Arkar Lwin

59
이 솔루션은 OP가 배우고 자하는 기능적 프로그래밍 원칙과 직접적으로 상충됩니다. 함수형 프로그래밍의 기본 규칙은 동일한 인수로 함수를 호출 할 때마다 항상 동일한 출력을 얻는 것입니다. 이렇게하면 전역 상태를 통해 발생하는 독사 버그가 발생하지 않습니다. maptest는 막대의 외부 정의에 의존하기 때문에이 원칙이 깨집니다.
image_doctor

3
Dear Stack overflow, 질문을 닫고 적당히 무겁기 때문에이 질문에 답으로 표시하고 정답을 답변으로 표시하지 않겠습니까? 감사합니다.
Bahadir Cambel

1
@image_doctor, FP에서는 글로벌 상수에 접근하는 것이 좋습니다 (널리 기능으로 간주)
Peter K

1
@BahadirCambel 스택 오버플로 조정은 때때로 처리가 무거울 수 있지만 항상 확인 표시가 항상 OP에 속합니다.
wizzwizz4

194

다른 기능 언어에 익숙하십니까? 즉, 파이썬이 함수형 프로그래밍을 수행하는 방법을 배우려고합니까, 또는 함수형 프로그래밍에 대해 배우고 파이썬을 차량으로 사용하려고합니까?

또한 목록 이해력을 이해합니까?

map(f, sequence)

직접 다음과 같습니다 (*).

[f(x) for x in sequence]

사실, 나는 map()파이썬 3.0에서 제거하기 위해 예정된 적이 있다고 생각 합니다.

map(f, sequence1, sequence2)

대부분 다음과 같습니다.

[f(x1, x2) for x1, x2 in zip(sequence1, sequence2)]

(시퀀스 길이가 다른 경우를 처리하는 방법에 차이가 있습니다. 보시다시피 map(), 시퀀스 중 하나가 부족하면 None을 채우고 zip()가장 짧은 시퀀스가 ​​중지되면 중지합니다)

따라서 특정 질문을 해결하기 위해 결과를 생성하려고합니다.

foos[0], bars
foos[1], bars
foos[2], bars
# etc.

단일 인수를 사용하여 인쇄 한 다음 막대가있는 함수를 작성하여이를 수행 할 수 있습니다.

def maptest(x):
     print x, bars
map(maptest, foos)

또는 다음과 같은 목록을 만들 수 있습니다.

[bars, bars, bars, ] # etc.

원래 maptest를 사용하십시오.

def maptest(x, y):
    print x, y

이를 수행하는 한 가지 방법은 미리 목록을 명시 적으로 작성하는 것입니다.

barses = [bars] * len(foos)
map(maptest, foos, barses)

또는 itertools모듈을 잡아 당길 수 있습니다. itertools파이썬에서 함수형 게으른 평가 프로그래밍을 수행하는 데 도움이되는 많은 영리한 함수가 포함되어 있습니다. 이 경우, itertools.repeat반복 할 때 인수를 무한정 출력하는을 원합니다 . 이 마지막 사실은 다음과 같은 경우를 의미합니다.

map(maptest, foos, itertools.repeat(bars))

map()인수 중 하나가 여전히 출력을 생성하는 한 계속 진행 되므로 끝없는 출력을 얻을 수 있습니다. 그러나 itertools.imap는 (와 map()) 같지만 가장 짧은 반복 가능한 중지가 멈추자 마자 중지됩니다.

itertools.imap(maptest, foos, itertools.repeat(bars))

도움이 되었기를 바랍니다 :-)

(*) 파이썬 3.0에서는 약간 다릅니다. 거기에서 map ()은 본질적으로 생성기 표현식을 반환합니다.


따라서지도와 달리 itertools.imap(f, sequence1, sequence2)실제로는 동등한 지 올바르게 이해 하고 [f(x1, x2) for x1, x2 in zip(sequence1, sequence2)]있습니까?
Jon Coombs

조금 테스트 해보면 itertools.imap 객체를 반환한다는 것을 알았을 것입니다. 아마도 이것은 더 '동등한'것입니다.list(itertools.imap(f, sequence1, sequence2))
Jon Coombs

승인 된 답변이어야합니다.
Rob Grant

30

찾고있는 솔루션은 다음과 같습니다.

>>> 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])]

[(x, bars) for x in foos]매 반복마다 함수 호출의 오버 헤드 (매우 중요 할 수 있음)를 피하기 때문에 맵을 사용하는 것보다 목록 이해 ( 부분)를 사용하는 것이 좋습니다 . for 루프에서 사용하려는 경우 생성기 이해를 사용하여 더 나은 속도를 얻을 수 있습니다.

>>> 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])

차이점은 발전기 이해력이 느리게로드 된다는 것 입니다.

UPDATE 이 댓글에 응답 :

물론 막대를 복사하지 않으면 모든 항목이 동일한 막대 목록입니다. 따라서 원본 막대를 포함하여 그 중 하나를 수정하면 모든 막대가 수정됩니다.

이것이 유효한 포인트라고 생각합니다. 내가 생각할 수있는 두 가지 해결책이 있습니다. 가장 효율적인 것은 아마도 다음과 같습니다.

tbars = tuple(bars)
[(x, tbars) for x in foos]

튜플은 변경할 수 없으므로이 목록 이해 (또는 해당 경로로 이동하면 생성기 이해) 결과를 통해 막대가 수정되지 않습니다. 결과 각각을 수정해야하는 경우 다음을 수행 할 수 있습니다.

from copy import copy
[(x, copy(bars)) for x in foos]

그러나 이것은 메모리 사용량과 속도면에서 약간 비쌀 수 있으므로 실제로 각 메모리에 추가 해야하는 경우가 아니라면 권장하지 않는 것이 좋습니다.


1
물론 막대를 복사하지 않으면 모든 항목이 동일한 막대 목록입니다. 따라서 원본 막대를 포함하여 그 중 하나를 수정하면 모든 막대가 수정됩니다.
vartec

20

함수형 프로그래밍은 부작용이없는 코드를 만드는 것입니다.

map은 기능적인 목록 변환 추상화입니다. 그것을 사용하여 일련의 무언가를 가져 와서 다른 일련의 것으로 바꿉니다.

반복자로 사용하려고합니다. 하지마 :)

다음은 map을 사용하여 원하는 목록을 작성하는 방법의 예입니다. 더 짧은 해결책이 있습니다 (단지 이해력을 사용하고 싶습니다). 그러나 이것은 조금 더 나은지도를 이해하는 데 도움이됩니다.

def my_transform_function(input):
    return [input, [1, 2, 3]]

new_list = map(my_transform, input_list)

이 시점에서 데이터 조작 만 수행했습니다. 이제 인쇄 할 수 있습니다 :

for n,l in new_list:
    print n, ll

- '루프없이'가 무슨 뜻인지 잘 모르겠습니다. fp는 루프를 피하는 것이 아닙니다 (목록을 방문하지 않고 목록의 모든 항목을 검사 할 수는 없음). 부작용을 피함으로써 버그를 줄입니다.


12
>>> 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]

11
import itertools

foos=[1.0, 2.0, 3.0, 4.0, 5.0]
bars=[1, 2, 3]

print zip(foos, itertools.cycle([bars]))

이것은 가장 쉽고 올바르게 작동하는 것입니다. 답변으로 동의하십시오
Phyo Arkar Lwin

1
이것은 단지 코드입니다. 설명이 없습니다. 많은 사용자들이이 답변의 의미를 이해하지 못합니다. @PhyoArkarLwin
ProgramFast

6

map(function, *sequences)함수 에 대한 매개 변수의 개요는 다음과 같습니다 .

  • function 함수의 이름입니다.
  • sequences일반적으로 목록 또는 튜플 인 시퀀스 수입니다. 동시에map 반복 하고 현재 값을에 제공합니다 . 이것이 시퀀스의 수가 함수의 매개 변수 수와 같아야하는 이유입니다.function

function의 매개 변수 중 일부를 반복하려고 하지만 다른 매개 변수는 일정하게 유지 하는 것으로 들리지만 불행히도 map지원하지 않습니다. 파이썬에 이러한 기능을 추가 하라는 오래된 제안 을 찾았 지만 맵 구성이 너무 깨끗하고 잘 설정되어 있으므로 구현이 어려울 것입니다.

다른 사람들이 제안한 것처럼 전역 변수 또는 목록 이해와 같은 해결 방법을 사용하십시오.


0

이거 할까?

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)

1
'bars'와 같은 maptest2 ()의 매개 변수를 호출 할 수 있습니다. 단수 bar는 실제로 전체 목록을 원할 때 반복되는 값을 받고 있음을 의미합니다.
Nikhil Chelliah

1
실제로 내가 믿는 반복되는 가치를 받고 있습니다.
Chris

0

이건 어때요:

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))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.