J'ai deux listes d'objets et j'ai besoin de trouver des objets correspondants selon deux ensembles d'attributs différents. Disons que j'ai des objets Vehicle () et que je dois d'abord faire correspondre tous les véhicules de la première liste qui correspondent aux véhicules de la seconde, en recherchant d'abord les couleurs correspondantes, puis les marques correspondantes. J'ai deux solutions, mais je ne suis pas sûr que ce soit la meilleure que je puisse faire. (J'ai vraiment besoin d'optimiser ces performances)
Disons que j'ai:
intersect_color_wise = [x for x in cars1 if x in cars2]
et des listes d'objets en tant que tels:
class Car(Vehicle): def __init__(self, color, brand): Vehicle.__init__(self,color, brand) def __hash__(self): return Vehicle.__hash__ def __eq__(self, other): if isinstance(other, Car): return other._color == self._color return False def change_to_car(obj): obj.__class__ = Car return obj cars1 = map(change_to_car, vehicles1) cars2 = map(change_to_car, vehicles2)
3 Réponses :
Quelle est la performance dans ce cas? Vous n'avez pas un ensemble complet de données pour émuler les performances pour des tests appropriés ...:
>>> get_intersections(vehicles1, vehicles2, "_brand", "_color") {'_brand': [<__main__.Vehicle object at 0x03588910>], '_color': [<__main__.Vehicle object at 0x035889D0>, <__main__.Vehicle object at 0x03588910>, <__main__.Vehicle object at 0x035889F0>]} >>> get_intersections(vehicles1, vehicles2, "_brand") {'_brand': [<__main__.Vehicle object at 0x03588910>]}
Vous pouvez également écrire des intersections individuelles si vous le souhaitez:
def get_intersections(list1, list2, *attrs:str): getter = attrgetter(*attrs) if len(attrs) > 1: sets = list(map(set, zip(*[getter(v) for v in list2]))) else: sets = [{getter(v) for v in list2}] results = {attr: [v for v in vehicles1 if getattr(v, attr) in sets[s]] for s, attr in enumerate(attrs)} return results
Merci pour votre suggestion. Mes données sont assez volumineuses en fait, donc je ne sais pas si je duplique des choses comme ça ... Et sur mon problème réel, je dois vérifier une liste d'attributs ...
Voir ma mise à jour, vous pouvez l'exécuter sur des attributs individuels avec attrgetter
. Pour autant que je puisse voir, le problème avec votre implémentation d'origine est la complexité de pour x en v1 ... pour y en v2
. mais vous n'avez vraiment pas besoin de vérifier plus d'une fois la v2
.
Ok, cela semble mieux, je vais vérifier et revenir vers vous Cependant, le problème est toujours que votre t_set duplique essentiellement mes données (car, généralement, les couleurs et les marques ne sont jamais les mêmes dans chaque liste - j'aurais dû présenter un exemple avec UserIds, etc. pour être plus clair)
En fait, Python est un langage dynamique. Cela signifie que vous pouvez modifier à volonté la classe Vehicle
pour l'adapter à vos besoins. Vous préparez 2 autres classes (je leur ai fait des sous-classes de Vehicle pour que l'auto-complétion fonctionne dans l'IDE) avec respectivement l'égalité de marque et l'égalité de couleur, et affectez simplement leurs membres à la classe Vehicle:
Vehicle.__eq__ = Vehicle_color.__eq__ Vehicle.__hash__ = Vehicle_color.__hash__ intersect_color_wise = [x for x in vehicles1 if x in vehicles2]
Pour obtenir intersection de marque:
Vehicle.__eq__ = Vehicle_brand.__eq__ Vehicle.__hash__ = Vehicle_brand.__hash__ intersect_brand_wise = [x for x in vehicles1 if x in vehicles2]
Ensuite pour obtenir l'intersection de couleur:
class Vehicle(object): def __init__(self, color, brand): self._color = color self._brand = brand class Vehicle_brand(Vehicle): def __eq__(self, other): return self._brand == other._brand def __hash__(self): return hash(self._brand) class Vehicle_color(Vehicle): def __eq__(self, other): return self._color == other._color def __hash__(self): return hash(self._color)
La bonne nouvelle ici, c'est que si votre La classe Véhicule
a d'autres membres, ils ne sont pas touchés lorsque vous modifiez la partie égalité, et vous ne copiez ni ne dupliquez aucun objet: seulement 2 méthodes dans les objets de classe.
Il se peut très OO pur, mais ça devrait marcher ...
Question: Vérification de l'égalité des objets suivant différentes attrbutes
Au lieu de trouver des objets égaux par la suite, en effectuant une
boucle en boucle
, vérifiez l ' égalité lors de l'instanciation.
Pour enregistrer lamémoire
, enregistrez uniquement les hachages égaux des objets.
Utilisez des
attributs de classe
pour contenir undict
desobjets
deset 1
et uneliste
pour contenir le_hash
d'objets égaux.
intersection:[2125945310] vehicle:color:red, brand:fiatEnregistrer une référence d'objets
set 1
dans ledict ref1
.
Vérifiez uniquement les objets deset 2
par rapport audict ref1
et enregistrez uniquement si égal .for vehicle in VehicleDiff.intersection(): print('vehicle:{}'.format(vehicle))Aide
methode intersection
pour obtenir un objetVehicleDiff
à partir de_hash
.for p in [('blue', 'fiat'), ('red', 'volvo'), ('red', 'fiat')]: VehicleDiff(1, *p) for p in [('blue', 'volvo'), ('red', 'BMW'), ('red', 'fiat')]: VehicleDiff(2, *p)Représentation sous forme de chaîne d'un objet
VehicleDiff
.def __str__(self): return 'color:{}, brand:{}'.format(self.color, self.brand)Il n'est pas nécessaire de conserver les objets dans une
liste
.Remarque : comme les données d'exemple données n'ont pas d'intersection, j'ai ajouté
('red', 'fiat')
àset 2
@staticmethod def intersection(): print('intersection:{}'.format(VehicleDiff._intersection)) for _hash in VehicleDiff._intersection: yield VehicleDiff.ref1[_hash]Imprimez le résultat, le cas échéant .
_hash = hash((color, brand)) if set == 1: VehicleDiff.ref1[_hash] = self elif _hash in VehicleDiff.ref1: VehicleDiff._intersection.append(_hash)Sortie :
class VehicleDiff: ref1 = {} _intersection = [] def __init__(self, set, color, brand): self.color = color self.brand = brandTesté avec Python: 3.4.2
Que faire si vous obtenez d'abord le
ensemble
demarques
etcouleurs
dans la liste de comparaison? c'est-à-diremarques = {v._brand pour v dans les véhicules2}; matches = [v pour v dans les véhicules1 si v._marque dans les marques]
? Il élimine la complexité de l'itération survéhicules2
pour chaque itérationvéhicules1
.L'exigence explicite obtient-elle deux intersections distinctes?
obj .__ class__ = Voiture
- woahhh, mauvaise idée.@meowgoesthedog pouvez-vous expliquer cela?
@kebanus Oui, j'ai besoin de deux intersections séparées
Les attributs tels que
__class__
sont réservés et ne doivent pas être écrits; vous devriez plutôt construire une nouvelle instance deCar
. (Bien que pour cet exemple, tout va bien)@meowgoesthedog c'est ce que je voulais en premier lieu mais quelque chose comme Car (myvehicle) jette une TypeError. Avez-vous par hasard une suggestion?
Pourriez-vous ajouter quelques exemples d'attentes? Je pense que je comprends votre exigence, mais ... Ce que je ferais: construire 2 dictionnaires clés (couleur, marque). Construisez ensuite 2 ensembles à partir de leurs clés. Trouvez une intersection d'ensemble, qui donne des clés communes.