# Mengen

# eine Menge über ein Set-Literal erzeugen
s1 = {1, 2, 3, 4, 5, 6}

# ein Element hinzufügen
s1.add(7)

# das vorhandene Element 6 mit remove() löschen
s1.remove(6)
print(s1)

# ein nochmaliges Löschen schlägt fehl, da es das Element 6 nicht gibt
try:
    s1.remove(6)
except Exception as e:
    if 0:
        # mit pass können wir die Ausnahme ignorieren
        pass
    else:    
        # wir melden die Ausnahme
        print(type(e), e)

print(s1)

# bei discard() statt remove() existiert dieses Problem nicht, dort wird keine
# Ausnahme generiert
s1.discard(6)
print(s1)

# Set Comprehension
s = {(x, y) for x in range(2) for y in range(3)}
print(s)

# 2 Sets generieren
s1 = set(range(10))
s2 = frozenset(range(5, 15)) # eine unveränderliche Menge

# 3 Varianten, die dieselbe Menge erzeugen
s3 = set([x ** 3 for x in range(10)]) # via List Comprehension
s3 = set(x ** 3 for x in range(10))   # über einen Generatorausdruck
s3 = {x ** 3 for x in range(10)}      # mit Set Comprehension

print(s1 & s2) # Schnittmenge
print(s2 & s3)
print(s1 | s2) # Vereinigungsmenge
print(s1 - s2) # Differenz
print(s1 ^ s2) # symmetrische Differenz (Vereinigungsmenge - Schnittmenge)

# Ermittlung der Python Keywords
#   import keyword
#   keyword.kwlist
keywords_python2 = [
  'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif',
  'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import',
  'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try',
  'while', 'with', 'yield'
]

keywords_python3 = [
  'False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break',
  'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally',
  'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal',
  'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield'
]

kw2 = frozenset(keywords_python2)
kw3 = frozenset(keywords_python3)

print('\nKeywords nur in Python 2')
print(kw2 - kw3)

print('\nKeywords nur in Python 3')
print(kw3 - kw2)

print('\nsymmetrische Differenz der Keywords von Python 2 und 3')
print(kw3 ^ kw2)

print('\nsortierte, dublettenfreie Liste aller Keywords von Python 2 und 3')
print(sorted(frozenset(keywords_python2 + keywords_python3)))

# eine fallend nach der Elementanzahl sortierte Liste der Tupel
# (Anzahl, Element) generieren
l = list(range(10)) + list(range(20)) + list(range(15))
print(
  sorted(
    # mit set(l) oder frozenset(l) erhalten wir die dublettenfreie Menge der
    # Listenelemente
    [(l.count(x), x) for x in frozenset(l)],
    reverse = True
  )
)

# mit Generatorausdruck statt List comprehension; da der Generatorausdruck hier
# nicht das einzige Funktionsargument ist, muss er in runde Klammern
# eingeschlossen werden
print(sorted(((l.count(x), x) for x in frozenset(l)), reverse=True))
