Seite 1 von 1

Objekte in Listen nach Attribut prüfen

Verfasst: Montag 30. November 2020, 17:26
von pystar
Hallo Zusammen,

leider bin ich in Python noch nicht so versiert, deshalb stehe ich gerade auf dem Schlauch beim filtern von Objekten.

In einer Liste habe ich Benutzer gespeichert. Jetzt will ich die Benutzer aus der Liste in eine andere Liste schreiben, aber nur, wenn es den Benutzer mit der Mail-Adresse noch nicht in der neuen Liste gibt.

Aus lauter Verzweiflung ;) habe ich den Code so geschrieben, dass er die org. Liste durchläuft und alle Mail-Adressen in einer Mail-Liste speichert.
Die kann ich dann mit 'in' prüfen ob es die Mail schon gibt. Siehe Beispiel:

Code: Alles auswählen

class Benutzer:

    def __init__(self, vorname, nachname, mail):
        self.vorname = vorname
        self.nachname = nachname
        self.mail = mail


benutzerliste = []

benutzerliste.append(Benutzer('Hans', 'Dampf', 'hans@dampf.de'))
benutzerliste.append(Benutzer('Hans', 'Luft', 'Hans@Luft.de'))
benutzerliste.append(Benutzer('Hans', 'imGlueck', 'Hans@imGlueck.de'))
benutzerliste.append(Benutzer('Hans', 'Falsch', 'Hans@Luft.de'))


mailListe = []
neueBenutzerListe = []
for user in benutzerliste:
    if user.mail not in mailListe:
        mailListe.append(user.mail)
        neueBenutzerListe.append(user)


for user in neueBenutzerListe:
    print(user.vorname, ' ', user.nachname, ' ', user.mail)


Geht das nicht einfacher?
So das ich in der ersten 'for user in benutzerliste:' schon auf das Attribut mail prüfen kann?

beste Grüße
pystar

Re: Objekte in Listen nach Attribut prüfen

Verfasst: Montag 30. November 2020, 17:38
von Sirius3
Variablennamen schreibt man komplett kein, und man schreibt keine Datentypen in den Namen. Und statt der mail-Liste würde man aus Effizienzgründen ein Set nehmen:

Code: Alles auswählen

class Benutzer:
    def __init__(self, vorname, nachname, mail):
        self.vorname = vorname
        self.nachname = nachname
        self.mail = mail


alle_benutzer = [
    Benutzer('Hans', 'Dampf', 'hans@dampf.de'),
    Benutzer('Hans', 'Luft', 'Hans@Luft.de'),
    Benutzer('Hans', 'imGlueck', 'Hans@imGlueck.de'),
    Benutzer('Hans', 'Falsch', 'Hans@Luft.de')
]

seen_emails = set()
neue_benutzer = []
for user in alle_benutzer:
    if user.mail not in seen_emails:
        seen_emails.add(user.mail)
        neue_benutzer.append(user)

for user in neue_benutzer:
    print(f"{user.vorname} {user.nachname} {user.mail}")
Man könnte natürlich auch einen komplizierten Ausdruck schreiben, aber das wäre kompliziert und wenig effizient:

Code: Alles auswählen

from operator import attrgetter
neue_benutzer = []
for user in alle_benutzer:
    if user.mail not in map(attrgetter('mail'), neue_benutzer):
        neue_benutzer.append(user)

Re: Objekte in Listen nach Attribut prüfen

Verfasst: Montag 30. November 2020, 19:09
von pystar
Super, besten Dank für die Tipps.
camelcase, das verrät meinen Java-Ursprung ;)

Aber das Vorgehen mit den zwei Listen (bzw. eine Liste und ein Set) um die Attribute aus der List zu filtern, ist in Python so gedacht?

Beste Grüße und vielen Dank

Re: Objekte in Listen nach Attribut prüfen

Verfasst: Montag 30. November 2020, 19:20
von __blackjack__
@pystar: Was heisst „in Python so gedacht“? Das würde man doch in anderen Sprachen genau so machen. Was wäre die Alternative? Es gäbe da schon fertig etwas im externen `more_itertools`-Modul. Für das folgende braucht man auch noch das externe `attr`-Modul, oder man müsste sich den Code für die `repr()`-Darstellung vom `Benutzer` selber schreiben:

Code: Alles auswählen

#!/usr/bin/env python3
from operator import attrgetter
from pprint import pprint

from attr import attrs, attrib
from more_itertools import unique_everseen


@attrs(frozen=True)
class Benutzer:
    vorname = attrib()
    nachname = attrib()
    mail = attrib()


def main():
    alle_benutzer = [
        Benutzer("Hans", "Dampf", "hans@dampf.de"),
        Benutzer("Hans", "Luft", "Hans@Luft.de"),
        Benutzer("Hans", "imGlueck", "Hans@imGlueck.de"),
        Benutzer("Hans", "Falsch", "Hans@Luft.de"),
    ]
    gefilterte_benutzer = list(
        unique_everseen(alle_benutzer, attrgetter("mail"))
    )
    pprint(gefilterte_benutzer)


if __name__ == "__main__":
    main()
Ausgabe:

Code: Alles auswählen

[Benutzer(vorname='Hans', nachname='Dampf', mail='hans@dampf.de'),
 Benutzer(vorname='Hans', nachname='Luft', mail='Hans@Luft.de'),
 Benutzer(vorname='Hans', nachname='imGlueck', mail='Hans@imGlueck.de')]

Re: Objekte in Listen nach Attribut prüfen

Verfasst: Sonntag 6. Dezember 2020, 15:39
von pystar
Danke für eure Antworten!
Mich hat einfach nur interessiert ob es evtl. einen Iterator gibt der über die Objekte iteriert und nach ein Attribut filtert. Dafür müsste sichergestellt sein, dass nur Objekte des passenden Typs in der Liste sind.
Ich mach es mit der Liste.

Beste Grüße
pystar

Re: Objekte in Listen nach Attribut prüfen

Verfasst: Sonntag 6. Dezember 2020, 23:25
von LeSchakal
Da die Mailadresse ja eindeutig ist, könnte man es auch ohne Importe lösen:

Code: Alles auswählen

class User:
    def __init__(self, prename, surname, email):
        self.prename = prename
        self.surname = surname
        self.email = email

    def __hash__(self):
        return hash(self.email)

    def __eq__(self, other):
        if not isinstance(other, User):
            return NotImplemented
        return self.email == other.email

def main():
    users = [
        User("Hans", "Dampf", "hans@dampf.de"),
        User("Hans", "Luft", "Hans@Luft.de"),
        User("Hans", "imGlueck", "Hans@imGlueck.de"),
        User("Hans", "Falsch", "Hans@Luft.de"),
    ]
    for user in set(users):
        print(f'{user.prename} {user.surname}, {user.email}')

if __name__ == "__main__":
    main()