it-swarm.com.de

Finden Sie ein Objekt in der Liste, dessen Attribut einem Wert entspricht (der alle Bedingungen erfüllt).

Ich habe eine Liste von Objekten. Ich möchte ein (erstes oder sonstiges) Objekt in dieser Liste finden, dessen Attribut (oder das Ergebnis der Methode - was auch immer) gleich value ist. 

Was ist der beste Weg, um es zu finden?

Hier ist ein Testfall:

  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

Ich denke, dass die Verwendung von Generatoren und reduce() keinen Unterschied macht, da es immer noch eine Liste durchlaufen würde.

ps .: Die Gleichung zu value ist nur ein Beispiel. Natürlich möchten wir ein Element erhalten, das alle Bedingungen erfüllt.

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

Dies ruft das erste Element aus der Liste ab, das der Bedingung entspricht, und gibt None zurück, wenn kein Element passt. Es ist meine bevorzugte Form für einen Ausdruck.

Jedoch,

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

Die naive Loop-Break-Version ist perfekt Pythonic - sie ist kurz, klar und effizient. Um es dem Verhalten des Einliners anzupassen:

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

Dies wird None zu x zuweisen, wenn Sie break nicht außerhalb der Schleife sind.

286
agf

Da es nicht nur zur Fertigstellung erwähnt wurde ..__ Der gute alte Filter filtert Ihre zu filternden Elemente.

Funktionsprogrammierung 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.

Ich weiß, dass im Allgemeinen in der Python-Liste Verständnisvorstellungen bevorzugt werden oder zumindest .__ das ist, was ich lese, aber ich sehe das Problem nicht als ehrlich an. Natürlich ist Python keine FP Sprache, aber Map/Reduce/Filter sind perfekt lesbar und die Standardanwendungen der funktionalen Programmierung. 

Hier bitteschön. Kennen Sie Ihre funktionale Programmierung. 

filterzustandsliste

Einfacher geht es nicht:

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

Ich bin gerade auf ein ähnliches Problem gestoßen und habe eine kleine Optimierung für den Fall entwickelt, in dem kein Objekt in der Liste die Anforderung erfüllt.

Zusammen mit der Liste test_list verwende ich ein zusätzliches Set test_value_set, das aus Werten der Liste besteht, nach denen ich filtern muss. Hier wird der sonstige Teil der agf-Lösung sehr schnell.

1
user1578297

Sie können auch einen umfangreichen Vergleich über die __eq__ - Methode für Ihre Test-Klasse implementieren und in-Operator ..__ verwenden Vergleiche Test Instanzen, die auf value basieren, woanders, dies könnte nützlich sein.

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
tm-

Für den folgenden Code ist xGen ein anonomischer Generatorausdruck, yFilt ist ein Filterobjekt. Beachten Sie, dass für xGen der zusätzliche Parameter None zurückgegeben wird, anstatt die StopIteration auszugeben, wenn die Liste erschöpft ist.

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

Ausgabe:

<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
0
edW