web-dev-qa-db-fra.com

Rechercher un objet dans une liste dont l'attribut est égal à une valeur (qui remplit n'importe quelle condition)

J'ai une liste d'objets. Je veux trouver un objet (premier ou autre) dans cette liste qui a un attribut (ou un résultat de méthode - peu importe) égal à value 

Quel est le meilleur moyen de le trouver?

Voici le cas de test:

  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

Je pense que l'utilisation de générateurs et de reduce() ne fera aucune différence, car ce serait tout de même parcourir la liste.

ps .: L'équation à value n'est qu'un exemple. Bien sûr, nous voulons obtenir un élément qui réponde à toutes les conditions.

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

Cela obtient le premier élément de la liste qui correspond à la condition et renvoie None si aucun élément ne correspond. C'est ma forme préférée d'expression unique.

Cependant,

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

La version naïve à rupture de boucle est parfaitement Pythonic - elle est concise, claire et efficace. Pour faire correspondre le comportement du one-liner:

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

Ceci assignera None à x si vous n'avez pas break sorti de la boucle.

286
agf

Puisqu'il n'a pas été mentionné juste pour l'achèvement . Le bon vieux filtre pour filtrer vos éléments à filtrer.

Programmation fonctionnelle 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.

Je sais que généralement dans les listes python, la compréhension est préférable ou du moins. C'est ce que je lis, mais je ne vois pas la question honnêtement. Bien sûr, le langage Python n’est pas un langage FP, mais les fonctions Mappage/Réduction/Filtre sont parfaitement lisibles et constituent le cas le plus standard des cas d’utilisation standard en programmation fonctionnelle. 

Alors voilà. Connais ta programmation fonctionnelle. 

liste des conditions de filtrage

Cela ne sera pas plus facile que cela:

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

Je viens juste de rencontrer un problème similaire et de concevoir une petite optimisation pour le cas où aucun objet de la liste ne répond à l'exigence (pour mon cas d'utilisation, cela entraînait une amélioration majeure des performances):

En plus de la liste test_list, je conserve un ensemble supplémentaire test_value_set, constitué des valeurs de la liste que je dois filtrer. Donc, ici, la partie restante de la solution d’agf devient très rapide.

1
user1578297

Vous pouvez également implémenter une comparaison enrichie via __eq__ pour votre classe Test et utiliser in opérateur . Il est nécessaire de comparer les instances de Test basées sur value ailleurs, cela pourrait être utile.

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-

Pour le code ci-dessous, xGen est une expression génératrice autonome, yFilt est un objet filtre. Notez que pour xGen, le paramètre supplémentaire Aucun est renvoyé plutôt que de lancer StopIteration lorsque la liste est épuisée.

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

Sortie:

<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