Duplikate und bestimmten Tupelwert aus Liste entfernen, zufälliges Tupel auswählen, Werte extrahieren

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

Hallo

Ich würde gerne aus einer Liste mit mehreren Tupelwerten sowohl alle Duplikate als auch einen bestimmten Tupelwert herausfiltern. Danach soll aus den übrigen Tupeln eines zufällig ausgewählt und dessen Werte extrahiert werden. Dazu habe ich mir beispielhaft folgenden Code geschrieben:

Code: Alles auswählen

from random import choice

a = [(567, 898), (345, 435), (324, 567), (567, 898)]
b = set()
b.add(number for number in a if number is not (345, 435))
numbers = choice(list(b))
i, j = numbers
print(i, j)
Mit der Umwandlung in ein `set()` sollen Duplikate entfernt und durch die Comprehension soll ein bestimmter Tupelwert nicht zum `set()` hinzugefügt werden. Anschließend soll mit der Methode `choice()` ein zufälliges Tupel ausgewählt werden. Die Zahlenwerte aus dem Tupel sollen dann Variablen zugewiesen werden. Leider funktioniert das nicht so wie gedacht. Es erscheint folgende Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/ata/source/test/main.py", line 7, in <module>
    i, j = numbers
ValueError: too many values to unpack (expected 2)
Wie macht man das besser?

Gruß
Atalanttore
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Hast Du Dir mal angeschaut, was Du da dem Set hinzufügst?

Einfacher ist es, erst das Set mit dem ganzen Listeninhalt zu erzeugen und dann die nicht gewünschen Elemente zu entfernen.
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

``is not`` ist auch falsch. Du vergleichst da mit einem literalen Tupel, das extra für den Vergleich erstellt wird, das ist nie das *selbe*, das kann höchstens *ungleich* sein. Das ist nicht das Selbe. :-)

Code: Alles auswählen

In [144]: a = [(567, 898), (345, 435), (324, 567), (567, 898)]

In [145]: a[1]
Out[145]: (345, 435)

In [146]: a[1] is not (345, 435)
Out[146]: True

In [147]: a[1] != (345, 435)
Out[147]: False
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

@Sirius3 + __blackjack__: Danke für die wertvollen Tipps.

Mit relativ wenigen Änderungen konnte ich den Code nun lauffähig machen.

Code: Alles auswählen

from random import choice

a = [(567, 898), (345, 435), (324, 567), (567, 898)]
b = set()
b.update(number for number in a if number != (345, 435))
numbers = choice(list(b))
i, j = numbers
print(b)
print(i, j)
Gruß
Atalanttore
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

Besser so:

Code: Alles auswählen

b = set(a)
b.discard((345,435))
i, j = choice(list(b))
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

@Sirius3: Welche Vorteile hat deine Lösung?

Gruß
Atalanttore
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Atalanttore: Einfacher und verständlicher‽
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

Hat die einfachere und verständlichere Lösung noch weitere Vorteile?
__deets__
User
Beiträge: 14536
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sie sollte auch schneller sein, aber warum sind einfach und verständlich nicht genug?
Atalanttore
User
Beiträge: 407
Registriert: Freitag 6. August 2010, 17:03

@__deets__: Für mich kann es nicht einfach genug sein. :)

Schön, wenn die einfache und verständliche Lösung auch noch schneller ist.

Gruß
Atalanttore
Benutzeravatar
DeaD_EyE
User
Beiträge: 1020
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Erst durch sets habe ich die Mengenlehre erst richtig verstanden.
Die Entscheidung dafür ein set zu verwenden, ist richtig gewesen.

Wenn man ein set nutzt, sollte man ein bisschen über Mengenlehre wissen.
Das ist sehr hilfreich.

Code: Alles auswählen

unique = {(567, 898), (345, 435), (324, 567), (567, 899)}
exclude = {(345, 435), (567, 899)}
unique_after = unique - exclude
Besser gleich als Funktion gestalten:

Code: Alles auswählen

def filter_unique(elements, exclude):
    elements = set(elements)
    exclude = set(exclude)
    return elements - exclude
Da elements und exclude in sets umgewandelt werden, können diese beiden Objekte auch Container oder Sequenzen sein.
Container enthalten Daten, haben aber keine Information über die Position. D.h. die Reihenfolge bleibt nicht erhalten.

Sets unterstützen unterschiedliche Operatoren. Am besten mal in die Dokumentation von Python gucken.
Oder als Abkürzung: https://realpython.com/python-sets/
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Antworten