목록에서 어떤 값과 동일한 속성을 가진 객체를 찾습니다 (조건에 부합)


221

개체 목록이 있습니다. 이 목록에서 속성 (또는 메소드 결과에 관계없이)이 하나 인 (첫 번째 또는 다른) 객체를 찾고 싶습니다 value.

그것을 찾는 가장 좋은 방법은 무엇입니까?

테스트 사례는 다음과 같습니다.

  class Test:
      def __init__(self, value):
          self.value = value

  import random

  value = 5

  test_list = [Test(random.randint(0,100)) for x in range(1000)]

  # that I would do in Pascal, I don't believe isn't anywhere near 'Pythonic'
  for x in test_list:
      if x.value == value:
          print "i found it!"
          break

나는 발전기를 사용한다고 생각 reduce()하지만 여전히 목록을 반복 할 것이기 때문에 아무런 차이가 없습니다.

추신 : 방정식 value은 단지 예입니다. 물론 우리는 어떤 조건에 맞는 요소를 원합니다.


2
이 질문에 대한 좋은 토론이 여기 있습니다 : tomayko.com/writings/cleanest-python-find-in-list-function
Andrew Hare

원래 게시물은 말도 안될 정도로 오래되었지만 두 번째 응답은 한 줄 버전과 정확히 일치합니다. 그래도 기본 루프 버전보다 낫다고 확신하지는 않습니다.
agf

답변:


433
next((x for x in test_list if x.value == value), None)

조건과 일치하는 목록에서 첫 번째 항목을 가져오고 일치하는 None항목이 없으면 반환 합니다. 내가 선호하는 단일 표현 양식입니다.

하나,

for x in test_list:
    if x.value == value:
        print "i found it!"
        break

순진한 루프 브레이크 버전은 완벽하게 Pythonic입니다. 간결하고 명확하며 효율적입니다. 원 라이너의 동작과 일치 시키려면 :

for x in test_list:
    if x.value == value:
        print "i found it!"
        break
else:
    x = None

루프를 벗어나지 않으면 할당 None됩니다 .xbreak


72
안심할 수있는 +1 "순진한 루프 브레이크 버전은 완벽하게 Pythonic입니다".
LaundroMat

훌륭한 해결책이지만 x.value가 실제로 해당 이름이 저장되는 x.fieldMemberName을 의미하도록 행을 수정하려면 어떻게해야합니까? field = "name"next ((test_list에서 x의 경우 x.field == value), None) 따라서이 경우에는 실제로 x.field가 아닌 x.name을 검사하고 있습니다.
Stewart Dale

3
@StewartDale 그것은 당신이 요구하는 것을 완전히 명확하지 않지만, 나는 당신이 의미하는 것 같아요 ... if getattr(x, x.fieldMemberName) == value. 에 x저장된 이름으로 속성을 가져 와서 fieldMemberName비교합니다 value.
agf

1
@ThatTechGuy-이 else절은 for루프가 아니라 루프 에 있어야 합니다 if. (거부 된 편집).
agf

1
@agf 와우 나는 문자 그대로 존재하는 줄 몰랐어 .. book.pythontips.com/en/latest/for_-_else.html cool!
ThatTechGuy

25

그것은 단지 완료를 위해 언급되지 않았기 때문에. 필터링 된 요소를 필터링하는 좋은 ol '필터.

기능적 프로그래밍 ftw.

####### Set Up #######
class X:

    def __init__(self, val):
        self.val = val

elem = 5

my_unfiltered_list = [X(1), X(2), X(3), X(4), X(5), X(5), X(6)]

####### Set Up #######

### Filter one liner ### filter(lambda x: condition(x), some_list)
my_filter_iter = filter(lambda x: x.val == elem, my_unfiltered_list)
### Returns a flippin' iterator at least in Python 3.5 and that's what I'm on

print(next(my_filter_iter).val)
print(next(my_filter_iter).val)
print(next(my_filter_iter).val)

### [1, 2, 3, 4, 5, 5, 6] Will Return: ###
# 5
# 5
# Traceback (most recent call last):
#   File "C:\Users\mousavin\workspace\Scripts\test.py", line 22, in <module>
#     print(next(my_filter_iter).value)
# StopIteration


# You can do that None stuff or whatever at this point, if you don't like exceptions.

나는 일반적으로 파이썬 목록에서 이해가 바람직하거나 적어도 그것이 읽은 것임을 알고 있지만 문제가 정직하지는 않습니다. 물론 파이썬은 FP 언어는 아니지만 Map / Reduce / Filter는 완벽하게 읽을 수 있으며 함수형 프로그래밍에서 가장 표준적인 표준 사용 사례입니다.

그래서 당신은 간다. 당신의 기능적 프로그래밍을 아십시오.

필터 조건 목록

이보다 더 쉬울 수는 없습니다.

next(filter(lambda x: x.val == value,  my_unfiltered_list)) # Optionally: next(..., None) or some other default value to prevent Exceptions

나는 이것의 스타일을 좋아하지만 두 가지 잠재적 인 문제가 있습니다. 1 : Python 3에서만 작동합니다. Python 2에서는와 filter호환되지 않는 목록을 반환합니다 next. 2 : 명확한 일치가 필요합니다. 그렇지 않으면 StopIteration예외 가 발생합니다.
freethebees

1
1 : 나는 파이썬 2를 모른다. 파이썬을 사용하기 시작할 때 파이썬 3은 이미 사용 가능했다. 불행히도 나는 파이썬 2의 스펙에 대해 실마리가 없다. 2. agf가 지적한 @freethebees. 예외 팬이 아닌 경우 next (..., None) 또는 다른 기본값을 사용할 수 있습니다. 또한 내 코드에 주석으로 추가했습니다.
니마 무사 비

@freethebees Point 2가 실제로 좋을 수도 있습니다. 목록에 특정 객체가 필요할 때 빠르게 실패하는 것이 좋습니다.
kap

7

간단한 예 : 다음 배열이 있습니다.

li = [{"id":1,"name":"ronaldo"},{"id":2,"name":"messi"}]

이제 배열에서 id가 1 인 객체를 찾고자합니다.

  1. next목록 이해와 함께 사용 방법
next(x for x in li if x["id"] == 1 )
  1. 목록 이해를 사용하고 첫 번째 항목을 반환
[x for x in li if x["id"] == 1 ][0]
  1. 커스텀 기능
def find(arr , id):
    for x in arr:
        if x["id"] == id:
            return x
find(li , 1)

위의 모든 방법을 출력하십시오. {'id': 1, 'name': 'ronaldo'}


1

방금 비슷한 문제가 발생하여 목록의 객체가 요구 사항을 충족하지 않는 경우에 대한 작은 최적화를 고안했습니다. (사용 사례의 경우 주요 성능이 향상되었습니다.)

test_list 목록과 함께 필터링해야 할 목록의 값으로 구성된 추가 test_value_set 세트를 유지합니다. 그래서 여기서 agf 솔루션의 else 부분은 매우 빠릅니다.


1

이런 식으로 할 수 있습니다

dict = [{
   "id": 1,
   "name": "Doom Hammer"
 },
 {
    "id": 2,
    "name": "Rings ov Saturn"
 }
]

for x in dict:
  if x["id"] == 2:
    print(x["name"])

그것이 긴 객체 배열에서 객체를 찾는 데 사용하는 것입니다.


질문자가 이미 시도한 것과 어떻게 다른가요?
Anum Sheraz

나는 그가 가장 간단한 방법으로 객체의 객체와 객체를 얻는 방법을 보여주고 싶었다.
Illud

0

클래스 및 사용 연산자에 __eq__대한 메소드를 통해 풍부한 비교를 구현할 수도 있습니다 . 이것이 최상의 독립 실행 형인지 확실하지 않지만 다른 곳을 기준으로 인스턴스 를 비교 해야하는 경우 유용 할 수 있습니다.TestinTestvalue

class Test:
    def __init__(self, value):
        self.value = value

    def __eq__(self, other):
        """To implement 'in' operator"""
        # Comparing with int (assuming "value" is int)
        if isinstance(other, int):
            return self.value == other
        # Comparing with another Test object
        elif isinstance(other, Test):
            return self.value == other.value

import random

value = 5

test_list = [Test(random.randint(0,100)) for x in range(1000)]

if value in test_list:
    print "i found it"

0

아래 코드에서 xGen은 익명 생성기 표현식이고 yFilt는 필터 객체입니다. xGen의 경우 목록이 소진 될 때 StopIteration을 발생시키지 않고 추가 None 매개 변수가 반환됩니다.

arr =((10,0), (11,1), (12,2), (13,2), (14,3))

value = 2
xGen = (x for x in arr if x[1] == value)
yFilt = filter(lambda x: x[1] == value, arr)
print(type(xGen))
print(type(yFilt))

for i in range(1,4):
    print('xGen: pass=',i,' result=',next(xGen,None))
    print('yFilt: pass=',i,' result=',next(yFilt))

산출:

<class 'generator'>
<class 'filter'>
xGen: pass= 1  result= (12, 2)
yFilt: pass= 1  result= (12, 2)
xGen: pass= 2  result= (13, 2)
yFilt: pass= 2  result= (13, 2)
xGen: pass= 3  result= None
Traceback (most recent call last):
  File "test.py", line 12, in <module>
    print('yFilt: pass=',i,' result=',next(yFilt))
StopIteration
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.