FOR 루프와 IF 문을 결합하는 파이썬 방식


266

for 루프와 if 문을 별도의 줄에 사용하는 방법을 알고 있습니다.

>>> a = [2,3,4,5,6,7,8,9,0]
... xyz = [0,12,4,6,242,7,9]
... for x in xyz:
...     if x in a:
...         print(x)
0,4,6,7,9

그리고 나는 다음과 같이 진술이 간단 할 때 목록 이해를 사용하여 이들을 결합 할 수 있다는 것을 알고 있습니다.

print([x for x in xyz if x in a])

그러나 내가 찾을 수없는 것은 for 루프와 if 문을 조합하여 발생하는 복잡한 명령 세트 ( "print x"뿐만 아니라)를 보여주는 어디에서나 (복사하고 배울 수있는) 좋은 예입니다. 내가 기대할만한 것 :

for x in xyz if x not in a:
    print(x...)

이것은 파이썬이 작동하는 방식이 아닙니까?


23
그것이 그렇게하는 방법입니다. 단순화하려고해서 지나치게 복잡하게 만들지 마십시오. 파이썬 이 모든 명시적인 for루프와 if문장 을 피하는 것은 아닙니다 .
Felix Kling

2
목록 이해에서 생성 된 목록을 for 루프로 사용할 수 있습니다. 그것은 마지막 예처럼 보일 것입니다.
Jacob

if 문이 이미 일치하는 값을 제외하고 for 루프의 반복 동안 목록이 지속적으로 증가하는 경우 처리로 넘어 가면 for 루프와 if 문을 결합하는 가장 빠른 방법은 무엇입니까?
ChewyChunks

3
@Chewy, 적절한 데이터 구조는 구문 설탕이 아닌 코드를 더 빠르게 만듭니다. 예를 들어, 목록 인 x in a경우 속도가 느립니다 a.
Nick Dandoulakis

1
이것은 해석 된 언어 인 파이썬입니다. 왜 코드가 얼마나 빠른지 논의하는 사람이 있습니까?
ArtOfWarfare

답변:


323

다음 과 같이 생성기 표현식을 사용할 수 있습니다 .

gen = (x for x in xyz if x not in a)

for x in gen:
    print x

1
gen = (y for (x,y) in enumerate(xyz) if x not in a)12입력 할 때 >>>를 반환 합니다 for x in gen: print x-왜 예기치 않은 동작이 열거됩니까?
ChewyChunks

9
가능하지만 원래 for 및 if 블록보다 좋지는 않습니다.
Mike Graham

1
@ChewyChunks. 작동하지만 열거에 대한 호출은 중복됩니다.
Johnsyweb

132
나는 파이썬에서 말할 수있는 것이 정말 그리워요for x in xyz if x:
bgusach

10
for x in (x for x in xyz if x not in a):나를 위해 일하지만 왜 당신이 할 수 없어야하는지 for x in xyz if x not in a:, 잘 모르겠습니다 ...
Matt Wenham

34

당으로 파이썬의 선 (당신은 당신의 코드, 즉 갈 수있는 곳 "파이썬"인지 궁금해하는 경우)

  • 못생긴 것보다 아름답습니다.
  • 암시적인 것보다 명시적인 것이 좋습니다.
  • 단순함이 복잡한 것보다 낫습니다.
  • 평평한 것이 중첩보다 낫습니다.
  • 가독성이 중요합니다.

두 가지 를 얻는 Pythonic 방법 은 다음과 같습니다.sorted intersectionset

>>> sorted(set(a).intersection(xyz))
[0, 4, 6, 7, 9]

또는 포함 xyz되지 않은 요소 a:

>>> sorted(set(xyz).difference(a))
[12, 242]

그러나 더 복잡한 루프의 경우 이름이 지정된 생성기 표현식 을 반복하고 이름이 지정된 함수를 호출하여 루프를 평평하게 할 수 있습니다. 한 줄에 모든 것을 맞추려고하는 것은 "피 토닉"이 아닙니다.


질문에 대한 추가 의견과 허용 된 답변에 따라 업데이트

나는 당신이 무엇을하려고하는지 확실하지 enumerate않지만 a, 사전 이라면 다음과 같이 키를 사용하고 싶을 것입니다.

>>> a = {
...     2: 'Turtle Doves',
...     3: 'French Hens',
...     4: 'Colly Birds',
...     5: 'Gold Rings',
...     6: 'Geese-a-Laying',
...     7: 'Swans-a-Swimming',
...     8: 'Maids-a-Milking',
...     9: 'Ladies Dancing',
...     0: 'Camel Books',
... }
>>>
>>> xyz = [0, 12, 4, 6, 242, 7, 9]
>>>
>>> known_things = sorted(set(a.iterkeys()).intersection(xyz))
>>> unknown_things = sorted(set(xyz).difference(a.iterkeys()))
>>>
>>> for thing in known_things:
...     print 'I know about', a[thing]
...
I know about Camel Books
I know about Colly Birds
I know about Geese-a-Laying
I know about Swans-a-Swimming
I know about Ladies Dancing
>>> print '...but...'
...but...
>>>
>>> for thing in unknown_things:
...     print "I don't know what happened on the {0}th day of Christmas".format(thing)
...
I don't know what happened on the 12th day of Christmas
I don't know what happened on the 242th day of Christmas

아래 의견에서 들리는 것처럼 발전기를 연구해야합니다. 나는 그들을 사용한 적이 없다. 감사. FOR와 IF 문의 동등한 조합보다 생성기가 더 빠릅니까? 나는 또한 세트를 사용했지만 때로는 목록의 중복 요소는 내가 버릴 수없는 정보입니다.
ChewyChunks

@ChewyChunks : 제너레이터가 파이썬이되는 유일한 방법은 아닙니다!
Johnsyweb

3
@Johnsyweb, 파이썬의 선 (Zen of Python)을 인용한다면 : "한가지 분명한 방법이 있어야합니다."
Wooble

@ Wooble : 있어야합니다. 나는 같은 시간 에 다른 질문에 대한 대답 에서 그 부분을 인용했습니다 !
Johnsyweb

18

나는 개인적으로 이것이 가장 예쁜 버전이라고 생각합니다.

a = [2,3,4,5,6,7,8,9,0]
xyz = [0,12,4,6,242,7,9]
for x in filter(lambda w: w in a, xyz):
  print x

편집하다

람다를 사용하지 않으려는 경우 부분 기능 응용 프로그램을 사용하고 연산자 모듈 (대부분의 연산자 기능을 제공함)을 사용할 수 있습니다.

https://docs.python.org/2/library/operator.html#module-operator

from operator import contains
from functools import partial
print(list(filter(partial(contains, a), xyz)))

4
filter(a.__contains__, xyz). 일반적으로 사람들이 람다를 사용할 때는 훨씬 더 간단한 것이 필요합니다.
Veky

당신이 뭔가를 잘못 이해했다고 생각합니다. __contains__다른 메소드와 마찬가지로 메소드입니다. 단지 특별한 메소드입니다. 즉, 운영자가 간접적으로 호출 할 수 있습니다 ( in이 경우). 그러나 직접 호출 할 수도 있으며 공개 API의 일부입니다. 개인 이름은 특수 메소드 이름에 대한 예외를 제공하기 위해 최대 하나의 마지막 밑줄을 갖는 것으로 정의되며 클래스 범위에서 어휘 적으로 이름이 변경 될 수 있습니다. docs.python.org/3/reference/datamodel.html#specialnamesdocs.python.org/3.6/tutorial/classes.html#private-variables를 참조하십시오 .
Veky

확실히 괜찮지 만 속성을 사용하여 액세스 할 수있는 메소드를 참조 할 수있는 두 개의 가져 오기는 이상하게 보입니다 (연산자는 일반적으로 이중 디스패치가 필요할 때 연산자가 사용되지만 inwrt right 피연산자가 단독으로 디스패치됩니다). 또한 name 아래의 method operator도 내보내 므로 반드시 개인 이름이 아닙니다. 모든 이중 밑줄이 "계속"을 의미하는 것은 아니라는 사실에 따라 생활하는 법을 배워야한다고 생각합니다. :-]contains__contains__
Veky

lambda다음을 포함하도록 수정해야 한다고 생각합니다 not. lambda w: not w in a, xyz
javadba

필터는 특히 람다 대신 정의 된 함수가되는 복잡한 조건의 경우 더욱
우아해

16

다음은 허용 된 답변의 단순화 / 한 라이너입니다.

a = [2,3,4,5,6,7,8,9,0]
xyz = [0,12,4,6,242,7,9]

for x in (x for x in xyz if x not in a):
    print(x)

12
242

(가) 통지 generator유지 인라인 . 이 테스트되었다 python2.7python3.6 합니다 (에 괄호를 알 print;))


10

아마 사용할 것입니다 :

for x in xyz: 
    if x not in a:
        print x...

@KirillTitov 예 python은 기본적으로 비 기능적 언어입니다 (이것은 순전히 명령형 코딩입니다. 저는이 답변의 저자가 python을 작성하는 방식이라는 것에 동의합니다. 기능을 사용하려고하면 읽기가 제대로되지 않거나 pythonic나는 내가 사용하는 다른 모든 언어 (scala, kotlin, javascript, R, swift, ..)로 기능적으로 코딩 할 수 있지만 파이썬에서는 어렵거나 어색하다
javadba

9
a = [2,3,4,5,6,7,8,9,0]
xyz = [0,12,4,6,242,7,9]  
set(a) & set(xyz)  
set([0, 9, 4, 6, 7])

매우 젠, @lazyr이지만 하나의 목록을 반복하고 다른 목록의 일치하는 요소를 무시하는 복잡한 코드 블록을 개선하는 데 도움이되지 않습니다. 첫 번째 목록을 집합으로 취급하고 증가하는 "무시"목록과의 결합 / 차를 비교하는 것이 더 빠릅니까?
ChewyChunks

이것을 시도import time a = [2,3,4,5,6,7,8,9,0] xyz = [0,12,4,6,242,7,9] start = time.time() print (set(a) & set(xyz)) print time.time() - start
Kracekumar

@ChewyChunks 반복 중에 목록 중 하나가 변경되면 무시 목록을 제외하고 각 요소를 무시 목록에 대해 확인하는 것이 더 빠를 것입니다. 세트 멤버쉽 확인은 매우 빠릅니다 if x in ignore: ....
Lauritz V. Thaulow

@lazyr 방금 무시 목록에 무시 세트 를 사용하여 코드를 다시 작성했습니다 . 처리 시간이 훨씬 느리게 나타납니다. (공평 if set(a) - set(ignore) == set([]):하게 말하자면 아마도 멤버쉽을 확인하는 것보다 속도가 느린 이유를 사용하여 비교하고 있었기 때문입니다. 나중에 작성중인 것보다 훨씬 간단한 예제로 다시 테스트하겠습니다.
ChewyChunks

5

당신이 사용할 수있는 발전기 발전기 표현이 너무 복잡하거나 복잡한 될 경우, 너무 :

def gen():
    for x in xyz:
        if x in a:
            yield x

for x in gen():
    print x

이것은 나에게 조금 더 유용합니다. 나는 발전기를 본 적이 없다. 그들은 무섭게 들립니다 (일반적으로 사용하기 힘든 모듈에서 보았 기 때문에).
ChewyChunks

2

사용 intersection또는intersection_update

  • 교차로 :

    a = [2,3,4,5,6,7,8,9,0]
    xyz = [0,12,4,6,242,7,9]
    ans = sorted(set(a).intersection(set(xyz)))
  • section_update :

    a = [2,3,4,5,6,7,8,9,0]
    xyz = [0,12,4,6,242,7,9]
    b = set(a)
    b.intersection_update(xyz)

    그럼 b네 대답은


2

내가 좋아하는 알렉스의 답변을 때문에, 필터가 정확하게 인 경우 목록에 적용되므로이 조건을 주어진 목록의 하위 집합을 탐구하려는 경우,이 가장 자연스러운 방법이 될 것 같습니다,

mylist = [1,2,3,4,5]
another_list = [2,3,4]

wanted = lambda x:x in another_list

for x in filter(wanted, mylist):
    print(x)

이 방법은 문제의 분리에 유용합니다. 조건 함수가 변경되면 피처링 할 유일한 코드는 함수 자체입니다.

mylist = [1,2,3,4,5]

wanted = lambda x:(x**0.5) > 10**0.3

for x in filter(wanted, mylist):
    print(x)

발전기 방법을 사용하면 목록의 구성원을하지 않을 경우 더 나은 것 같다,하지만 더 맞는 것 같다 고 말했다 구성원의 변경, 발전기

mylist = [1,2,3,4,5]

wanted = lambda x:(x**0.5) > 10**0.3

generator = (x**0.5 for x in mylist if wanted(x))

for x in generator:
    print(x)

또한 필터는 발전기와 작동하지만이 경우 효율적이지 않습니다.

mylist = [1,2,3,4,5]

wanted = lambda x:(x**0.5) > 10**0.3

generator = (x**0.9 for x in mylist)

for x in filter(wanted, generator):
    print(x)

그러나 물론 다음과 같이 작성하는 것이 좋습니다.

mylist = [1,2,3,4,5]

wanted = lambda x:(x**0.5) > 10**0.3

# for x in filter(wanted, mylist):
for x in mylist if wanted(x):
    print(x)

0

목록 a와 b의 고유 한 공통 요소를 찾는 간단한 방법 :

a = [1,2,3]
b = [3,6,2]
for both in set(a) & set(b):
    print(both)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.