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