python basics michael poeltl © 2011,2013,2015

set frozenset

Einleitung

Die Mengen in python (set-Objekte) wurden jenen der Mathematik nachempfunden.
Was aber ist das Besondere an Mengen?
Mengen sind UNGEORDNETE Ansammlungen von Objekten, die in dem Mengenobjekt nur ein Mal vorkommen.
Man kann sich also nicht auf einen Index stützen, um auf einen bestimmten Wert an einer gewissen Position im Verbund zu zeigen (wie bei str, list, tuple), noch hat man einen key, wie bei einem dictionary.

Und übergibt man eine geordnete Liste (set(geordnete_liste)), so hat man auch keine Gewähr, dass die Ordnung beibehalten wird. Das (Betriebs-)System entscheidet, wie bzw. wo die Daten im RAM liegen sollen, daher kann das von System zu System auch unterschiedliche Ausgaben liefern. Die Reihenfolge ist also bei ungeordneten Datentypen niemals ein Kriterium.

In python zählen zwei Objekt-Typen zu den Mengen:

wobei Objekte vom Typ set veränderbar (muteable) sind, was bei frozenset-Objekten nicht der Fall ist.
Es lassen sich sets im Nu zu einem frozenset umbauen und vice versa.

Welche Mengenoperationen gibt es?

Diese Mengenoperationen können auch an d.keys()- und d.items()-Objekten (d ist ein dict-Objekt) angewandt werden!

set

Gleich in-medias-res

>>> x = ( 1,1,2,2,3,3,4,5,6 )
>>> y = set( x )
>>> print( y )
{1, 2, 3, 4, 5, 6}
>>> print( type(y) )
<class 'set'>
>>> S4 = set()
>>> S3 = frozenset()
>>> print( type(S3) )
<class 'frozenset'>
>>>

so baut man sich also ein set; more samples

>>> a = { 1, 2, 3, 2, 3 }
>>> print( a )
{1, 2, 3}
>>> type( a )
<class 'set'>
>>>

Wir konnten auch die Funktionen set() und frozenset(), um leere Mengenobjekte zu erzeugen, denn es gilt immer noch
b = {} ergibt ein leeres dictionary-Objekt!

Ein set darf/kann nur unveränderbare Objekte enthalten!
Also...

Außerdem sind keine Verschachtelungen von sets möglich!

>>> menge = {2,[1,2],'a'}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>>

Schauen wir uns folgendes Paradebeispiel an, wo gecheckt wird, wie oft ein item in einer Sequenz vorkommt.

>>> wort = 'donaudampfschifffahrtsgesellschaft'
>>> for c in sorted(list(set(wort))):
...     print( '{}: {}x'.format( c, wort.count(c) ))
... 
a: 4x
c: 2x
d: 2x
e: 2x
f: 5x
g: 1x
h: 3x
i: 1x
l: 2x
m: 1x
n: 1x
o: 1x
p: 1x
r: 1x
s: 4x
t: 2x
u: 1x
>>>

Weiter geht's mit diversen Operationen.

>>> m1 = set( range(10) )
>>> m2 = set( range(5,15) )
>>> print( 'm1 vereinigt mit m2 = {}'.format( m1 | m2 ))
m1 vereinigt mit m2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
>>> print( 'm1 vereinigt mit m2 = {}'.format( m1.union( m2 ) ))
m1 vereinigt mit m2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
>>> print( 'Durchschnitt von m1 und m2 = {}'.format( m1 & m2 ))
Durchschnitt von m1 und m2 = {8, 9, 5, 6, 7}
>>> print( 'Durchschnitt von m1 und m2 = {}'.format( m1.intersection( m2 ) ))
Durchschnitt von m1 und m2 = {8, 9, 5, 6, 7}
>>> print( 'Die Elemente {} von m1 sind nicht in m2'.format( m1 - m2 ))
Die Elemente {0, 1, 2, 3, 4} von m1 sind nicht in m2
>>> print( 'Die Elemente {} von m2 sind nicht in m1'.format( m2.difference( m1 ) ))
Die Elemente {10, 11, 12, 13, 14} von m2 sind nicht in m1
>>>

Das erinnert mich schon sehr an die Mengenlehre der ersten Klasse Gymnasium.
| ist also gleich union() und & Durschschnitt (s1.intersection(s2).
Sehen wir uns anhand folgender Beispiele weitere set-Methoden an.

>>> m3 = set( range(5,10) )
>>> m3.issubset( m1 )
True
>>> m2.issuperset( m3 )
True
>>> m3.clear()
>>> m3.add( 'war leer' )
>>> print( m3 )
{'war leer'}
>>> m3.add( 'bins nimmer' )
>>> m4 = m3.copy()
>>> print( m4 )
{'bins nimmer', 'war leer'}
>>> 'nimmer' in m4
False
>>> 'nimmer' in m4[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'set' object does not support indexing
>>>

klar, dass das nicht geht - das set-Objekt ist ja ein UNGEORDNETer Typ --> keine index-Abfrage ( m4[0]) sinnvoll (who knows/cares what is on position 0!)

>>> m5 = m3
>>> print( 'id-m3: {0}\nid-m4: {1}\nid-m5: {2}'.format( id( m3 ), id( m4 ), id( m5 ) ))
id-m3: 3083592508
id-m4: 3083594300
id-m5: 3083592508
>>>

Die copy()-Methode von set hat also tatsächlich ein eigenes set-Objekt (eigene id) gebaut.
Mittels der discard()-Methode können wir ein item aus einem set entfernen (wenn Objekt-Angabe, das aus set-Objekt entfernt werden soll, gar nicht im set-Objekt enthalten ist, gibt es keinen Krach/Error/Exception) - wir werden im Anschluss noch die remove()-Methode kennenlernen, und die pop()-Methode, die wieder ein Objekt aus dem set-Objekt zum Auffangen aus dem set herauspoppt.
Es scheint zwar so zu sein, dass pop() das erste item vom set-Objekt herauspoppt, da es aber keine Positionen gibt, ist es unmöglich, von Position zu sprechen.

>>> m5.discard( 'mi gibts net in m5' )
>>> print( m5 )
{'bins nimmer', 'war leer'}
>>> m5.discard( 'bins nimmer' )
>>> print( m3 )
{'war leer'}
>>> m5 = m1.copy()
>>> m5.remove( 5 )
>>> m5.remove( 'a' )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'a'
>>> m5.pop()
0
>>> m5.pop()
1
>>> print( m5 )
{2, 3, 4, 6, 7, 8, 9}
>>>

Zum Thema echte Teilmenge vs unechte Teilmenge (subset)

>>> menge1 = { 0,1,2,3 }
>>> menge2 = { 1,2 }
>>> menge3 = set( range(4) )
>>> menge2 <= menge1
True
>>>

Menge2 ist Teilmenge von Menge1.
ist sie nun echte oder unechte Teilmenge von Menge1?

>>> menge2 < menge1
True
>>>

Menge2 IST ECHTE Teilmenge von Menge1

>>> menge3 <= menge1
True
>>> menge3 < menge1
False
>>> menge3.issubset( menge1 )
True
>>>

Menge3 ist zwar auch eine Teilmenge von Menge1, aber eine UNECHTE.

symmetric_difference()

m1.symmetric_difference(m2) lässt sich auch so schreiben:
m1 ^ m2
und das tut's:
vereinigt differenz m1-m2 mit m2-m1
(m1 - m2) | (m2 - m1)
also

>>> print( m1 )
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> print( m2 )
{5, 6, 7, 8, 9, 10, 11, 12, 13, 14}
>>> print( '(m1 - m2) | (m2 - m1) = {}'.format( m1.symmetric_difference( m2 )))
(m1 - m2) | (m2 - m1) = {0, 1, 2, 3, 4, 10, 11, 12, 13, 14}
>>> print( '(m1 - m2) | (m2 - m1) = {}'.format(  m1 ^ m2 ))
(m1 - m2) | (m2 - m1) = {0, 1, 2, 3, 4, 10, 11, 12, 13, 14}
>>>

und das erreichte man auch folgendermaßen

>>> m1.union( m2 ) - m1.intersection( m2 )
{0, 1, 2, 3, 4, 10, 11, 12, 13, 14}
>>>

die built-in-functons len(), max() oder min() (und wahrscheinlich noch andere) funktionieren freilich auch für (frozen)set-Objekte!

>>> print( max( m2 ))
14
>>> print( len( m1.symmetric_difference( m2 )))
10
>>>

Man fragt sich manchmal, warum es zum einen die set-Methoden gibt, und zum anderen die Zeichen wie
m1 ^ m2 gibt?
bei m1 & m2 MÜSSEN m1,m2 set/frozenset-Objekte sein, während bei set/frozenset-Methoden die übergebenen Objekte blo&zlig; iterierbar zu sein brauchen
SETOBJECT.symmetric_difference(STRING)
Beispiel:

>>> print( wort )
'donaudampfschifffahrtsgesellschaft'
>>> wort2 = 'superkalefragelistischexpigaligetisch'
>>> print( 'Die "symmetrische Differenz" von\n{}\nund\n{}\nist\n{}'.format( wort, wort2, set( wort ).symmetric_difference( wort2 )))
Die "symmetrische Differenz" von
donaudampfschifffahrtsgesellschaft
und
superkalefragelistischexpigaligetisch
ist
{'d', 'k', 'm', 'o', 'n', 'x'}
>>>

set comprehension

Wir kennen bereits list comprehension und dict comprehension.
Und so sind auch set-comprehensions eine bequeme Art, ein set-Objekt zu erzeugen.
Die Ähnlichkeit zu dict-comprehensions ist groß, also Vorsicht!

>>> s = { str(v) for v in range(1,15) if v%2 }
>>> print (type(s))
<class 'set'>
>>> print (s)
{'11', '13', '1', '3', '5', '7', '9'}
>>>

Man sieht wieder, wie schön unordentlich die items im set-Objekt liegen.

frozenset

frozenset-Objekte können NICHT verändert werden (immuteable).
Somit können frozensets-Objekte auch als key in einem dictionary eingesetzt werden oder Element eines set-Objektes sein.
Alle Methoden, die das set-Objekt nicht veränderten, gelten auch für frozensets.
Frozensets werden folgendermaßen erstellt

>>> m6 = frozenset('michael')
>>> m7 = frozenset('nicholas')
>>> print (type(m6))
<class 'frozenset'>
>>> print (m6.intersection(m7))
frozenset({'a', 'i', 'c', 'l', 'h'})
>>>

Was passiert, wenn ich frozenset mit set verbinde.

>>> wasbinich = m1.union(m7)
>>> print (type(wasbinich))
<class 'set'>
>>>

Es kommt also ein set-Objekt heraus.

>>> s_name = set(m7)
>>> print (type(s_name))
<class 'set'>
>>> f_name = frozenset(s_name)
>>> print (type(f_name))
<class 'frozenset'>
>>>

man kann also mühelos set zu frozenset-Objekt machen und vice versa.


Hier geht es zum Seitenanfang und da geht es zur python-Startsete