Me

Mengen in Python

16 Übungen

Über Mengen

Ein set ist eine veränderbare und ungeordnete Sammlung von hashbaren Objekten. Die Elemente eines Sets müssen verschieden sein. Doppelte Einträge sind nicht erlaubt. Sie können verschiedene Datentypen und sogar verschachtelte Strukturen wie ein tuple aus tuples enthalten, solange sich alle Elemente hashen lassen. Sets gibt es außerdem in einer unveränderbaren Variante: frozenset.

Sets werden am häufigsten verwendet, um schnell Duplikate aus anderen Datenstrukturen oder Elementgruppen zu entfernen. Sie werden auch für effiziente Vergleiche genutzt, wenn es nicht auf die Reihenfolge oder das Verfolgen von Duplikaten ankommt.

Wie andere Sammlungstypen (Wörterbücher, Listen, Tupel) unterstützen sets:

  • Iteration über for item in <set>,
  • Prüfung der Zugehörigkeit über in und not in,
  • Längenberechnung über len() und
  • flache Kopien über copy().

sets unterstützen nicht:

  • Indexzugriff jeder Art
  • Ordnung durch Sortieren oder Einfügen
  • Slicing
  • Verkettung über +

Die Prüfung der Zugehörigkeit in einem set hat (im Durchschnitt) eine konstante Zeitkomplexität, während sie bei einer list oder einem string mit der Länge der Daten wächst. Methoden wie <set>.union(), <set>.intersection() oder <set>.difference() haben (im Durchschnitt) ebenfalls eine konstante Zeitkomplexität.

Sets erstellen

Sets lassen sich auf viele verschiedene Arten erstellen. Am direktesten sind das Deklarieren eines Set-Literals, die Verwendung des Konstruktors der set-Klasse (set()) und eine Set-Comprehension.

Set-Literale

Ein set lässt sich direkt als Set-Literal mit geschweiften Klammern {} und Kommas zwischen den Elementen schreiben. Duplikate werden stillschweigend weggelassen:

>>> one_element = {'➕'}
{'➕'}

>>> multiple_elements = {'➕', '🔻', '🔹', '🔆'}
{'➕', '🔻', '🔹', '🔆'}

>>> multiple_duplicates =  {'Hello!', 'Hello!', 'Hello!', 
                            '¡Hola!','Привіт!', 'こんにちは!', 
                            '¡Hola!','Привіт!', 'こんにちは!'}
{'こんにちは!', '¡Hola!', 'Hello!', 'Привіт!'}

Set-Literale verwenden dieselben geschweiften Klammern wie dict-Literale. Ein leeres set erstellst du deshalb mit set().

Der Set-Konstruktor

set() (der Konstruktor der set-Klasse) kannst du mit jedem iterable aufrufen, das du als Argument übergibst. Die Elemente des iterable werden einzeln durchlaufen und dem set hinzugefügt. Die Reihenfolge der Elemente bleibt nicht erhalten, und Duplikate werden stillschweigend weggelassen:

# To create an empty set, the constructor must be used.
>>> no_elements = set()
set()

# The tuple is unpacked & each element is added.  
# Duplicates are removed.
>>> elements_from_tuple = set(("Parrot", "Bird", 
                               334782, "Bird", "Parrot"))
{334782, 'Bird', 'Parrot'}

# The list is unpacked & each element is added.
# Duplicates are removed.
>>> elements_from_list = set([2, 3, 2, 3, 3, 3, 5, 
                              7, 11, 7, 11, 13, 13])
{2, 3, 5, 7, 11, 13}

Set-Comprehensions

Wie lists und dicts lassen sich Sets über eine Comprehension erstellen:

# First, a list with duplicates
>>> numbers = [1,2,3,4,5,6,6,5,4,8,9,9,9,2,3,12,18]

# This set comprehension squares the numbers divisible by 3
# Duplicates are removed.
>>> calculated = {item**2 for item in numbers if item % 3 == 0}
{9, 36, 81, 144, 324}

Stolperfallen beim Erstellen von Sets

Wegen seines „Entpack“-Verhaltens kann die Verwendung des set-Konstruktors mit einem String überraschen:

# String elements (Unicode code points) are 
# iterated through and added *individually*.
>>> elements_string = set("Timbuktu")
{'T', 'b', 'i', 'k', 'm', 't', 'u'}

# Unicode separators and positioning code points 
# are also added *individually*.
>>> multiple_code_points_string = set('अभ्यास')
{'अ', 'भ', 'य', 'स', 'ा', '्'}

Zur Erinnerung: Sets können verschiedene Datentypen und verschachtelte Datentypen enthalten, aber alle Elemente eines set müssen hashbar sein:

# Attempting to use a list for a set member throws a TypeError
>>> lists_as_elements = {['🌈','💦'], 
                        ['☁️','⭐️','🌍'], 
                        ['⛵️', '🚲', '🚀']}

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'


# Standard sets are mutable, so they cannot be hashed.
>>> sets_as_elements = {{'🌈','💦'}, 
                        {'☁️','⭐️','🌍'}, 
                        {'⛵️', '🚲', '🚀'}}

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'

Ein set aus sets lässt sich jedoch über den Typ frozenset() erstellen:

# Frozensets don't have a literal form.
>>> set_1 = frozenset({'🌈','💦'})
>>> set_2 = frozenset({'☁️','⭐️','🌍'})
>>> set_3 = frozenset({'⛵️', '🚲', '🚀'})

>>> frozen_sets_as_elements = {set_1, set_2, set_3}
>>> frozen_sets_as_elements
{frozenset({'⛵️', '🚀', '🚲'}),
 frozenset({'🌈', '💦'}),
 frozenset({'☁️', '⭐️', '🌍'})}

Elemente eines Sets hinzufügen und entfernen

Elemente kannst du mit den Methoden <set>.add(<item>) und <set>.remove(<item>) zu einem set hinzufügen oder daraus entfernen. Die Methode .remove(<item>) löst einen KeyError aus, wenn das Element nicht im set vorhanden ist:

>>> creatures = {'crow', 'duck', 'fish', 'monkey', 'elephant'}
>>> creatures.add('beaver')
>>> creatures.remove('duck')
>>> creatures
{'beaver', 'crow', 'elephant', 'fish', 'monkey'}

# Trying to remove an item that is not present raises a KeyError
>>> creatures.remove('bear')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  KeyError: 'bear'

Weitere Möglichkeiten, Elemente aus einem Set zu entfernen

  • <set>.discard(<item>) entfernt ein Element aus dem set, löst aber keinen KeyError aus, wenn das Element nicht vorhanden ist.
  • <set>.clear() entfernt alle Elemente aus dem Set.
  • <set>.pop() entfernt ein beliebiges Element und gibt es zurück. Ist das set leer, wird ein KeyError ausgelöst.

Set-Operationen

Sets haben Methoden, die im Allgemeinen mathematische Mengenoperationen nachbilden. Die meisten (nicht alle) dieser Methoden haben eine Operator-Entsprechung. Methoden akzeptieren im Allgemeinen jedes iterable als Argument, während Operatoren verlangen, dass beide Seiten der Operation sets oder frozensets sind.

Zugehörigkeit zwischen Sets prüfen

Mit der Methode <set>.isdisjoint(<other_collection>) prüfst du, ob Elemente eines set mit den Elementen eines anderen überlappen. Die Methode akzeptiert jedes iterable oder set als Argument. Sie gibt True zurück, wenn die beiden Sets keine gemeinsamen Elemente haben, und False, wenn sich Elemente überschneiden.

# Both mammals and additional_animals are lists.
>>> mammals = ['squirrel','dog','cat','cow', 'tiger', 'elephant']
>>> additional_animals = ['pangolin', 'panda', 'parrot', 
                          'lemur', 'tiger', 'pangolin']

# Animals is a dict.
>>> animals = {'chicken': 'white',
               'sparrow': 'grey',
               'eagle': 'brown and white',
               'albatross': 'grey and white',
               'crow': 'black',
               'elephant': 'grey', 
               'dog': 'rust',
               'cow': 'black and white',
               'tiger': 'orange and black',
               'cat': 'grey',
               'squirrel': 'black'}
               
# Birds is a set.
>>> birds = {'crow','sparrow','eagle','chicken', 'albatross'}

# Mammals and birds don't share any elements.
>>> birds.isdisjoint(mammals)
True

# There are also no shared elements between 
# additional_animals and birds.
>>> birds.isdisjoint(additional_animals)
True

# Animals and mammals have shared elements.
# **Note** The first object needs to be a set or converted to a set
# since .isdisjoint() is a set method.
>>> set(animals).isdisjoint(mammals)
False

Teilmengen und Obermengen prüfen

Mit <set>.issubset(<other_collection>) prüfst du, ob jedes Element in <set> auch in <other_collection> enthalten ist. Die Operatorform ist <set> <= <other_set>:

# Set methods will take any iterable as an argument.
# All members of birds are also members of animals.
>>> birds.issubset(animals)
True

# All members of mammals also appear in animals.
# **Note** The first object needs to be a set or converted to a set
# since .issubset() is a set method.
>>> set(mammals).issubset(animals)
True

# Both objects need to be sets to use a set operator
>>> birds <= set(mammals)
False

# A set is always a loose subset of itself.
>>> set(additional_animals) <= set(additional_animals)
True

<set>.issuperset(<other_collection>) ist die Umkehrung von .issubset(). Damit prüfst du, ob jedes Element in <other_collection> auch in <set> enthalten ist. Die Operatorform ist <set> >= <other_set>:

# All members of mammals also appear in animals.
# **Note** The first object needs to be a set or converted to a set
# since .issuperset() is a set method.
>>> set(animals).issuperset(mammals)
True

# All members of animals do not show up as members of birds.
>>> birds.issuperset(animals)
False

# Both objects need to be sets to use a set operator
>>> birds >= set(mammals)
False

# A set is always a loose superset of itself.
>>> set(animals) >= set(animals)
True

Echte Teilmengen und Obermengen

Mit <set> < <other_set> und <set> > <other_set> testest du auf echte Teilmengen. Ein set ist eine echte Teilmenge, wenn für den <-Operator (<set> <= <other_set>) UND (<set> != <other_set>) gilt.

Ein set ist eine echte Obermenge, wenn für den >-Operator (<set> >= <other_set>) UND (<set> != <other_set>) gilt. Für diese Operatoren gibt es keine äquivalente Methode:

>>> animal_names = {'albatross','cat','chicken','cow','crow','dog',
                   'eagle','elephant','sparrow','squirrel','tiger'}

>>> animals_also = {'albatross','cat','chicken','cow','crow','dog',
                   'eagle','elephant','sparrow','squirrel','tiger'}

>>> mammals = {'squirrel','dog','cat','cow', 'tiger', 'elephant'}
>>> birds   = {'crow','sparrow','eagle','chicken', 'albatross'}

>>> mammals < animal_names
True

>>> animal_names > birds
True

# A set is not a *proper subset* if set == other set.
>>> animals_also < animal_names
False

# A set is never a *proper subset* of itself
>>> animals_also < animals_also
False

Vereinigung von Sets

<set>.union(*<other iterables>) gibt ein neues set mit den Elementen aus <set> und allen <other iterables> zurück. Die Operatorform dieser Methode ist <set> | <other set 1> | <other set 2> | ... | <other set n>.

>>> perennials = {'Asparagus', 'Broccoli', 'Sweet Potato', 'Kale'}
>>> annuals = {'Corn', 'Zucchini', 'Sweet Peas', 'Summer Squash'}
>>> more_perennials = ['Radicchio', 'Rhubarb', 
                      'Spinach', 'Watercress']

# Methods will take any iterable as an argument.
>>> perennials.union(more_perennials)
{'Asparagus','Broccoli','Kale','Radicchio','Rhubarb',
'Spinach','Sweet Potato','Watercress'}

# Operators require sets.
>>> set(more_perennials) | perennials
{'Asparagus',
 'Broccoli',
 'Kale',
 'Radicchio',
 'Rhubarb',
 'Spinach',
 'Sweet Potato',
 'Watercress'}

Differenz von Sets

<set>.difference(*<other iterables>) gibt ein neues set mit den Elementen des ursprünglichen <set> zurück, die nicht in <others> enthalten sind. Die Operatorversion dieser Methode ist <set> - <other set 1> - <other set 2> - ... - <other set n>.

>>> berries_and_veggies = {'Asparagus', 
                          'Broccoli', 
                          'Watercress', 
                          'Goji Berries', 
                          'Goose Berries', 
                          'Ramps', 
                          'Walking Onions', 
                          'Blackberries', 
                          'Strawberries', 
                          'Rhubarb', 
                          'Kale', 
                          'Artichokes', 
                          'Currants'}

>>> veggies = ('Asparagus', 'Broccoli', 'Watercress', 'Ramps',
               'Walking Onions', 'Rhubarb', 'Kale', 'Artichokes')

# Methods will take any iterable as an argument.
>>> berries = berries_and_veggies.difference(veggies)
{'Blackberries','Currants','Goji Berries',
 'Goose Berries', 'Strawberries'}

# Operators require sets.
>>> berries_and_veggies - berries
{'Artichokes','Asparagus','Broccoli','Kale',
'Ramps','Rhubarb','Walking Onions','Watercress'}

Schnittmenge von Sets

<set>.intersection(*<other iterables>) gibt ein neues set mit den Elementen zurück, die das ursprüngliche set und alle <others> gemeinsam haben (mit anderen Worten: das set, in dem sich alles schneidet). Die Operatorversion dieser Methode ist <set> & <other set> & <other set 2> & ... & <other set n>

>>> perennials = {'Annatto','Asafetida','Asparagus','Azalea',
                 'Winter Savory', 'Broccoli','Curry Leaf','Fennel', 
                 'Kaffir Lime','Kale','Lavender','Mint','Oranges',
                 'Oregano', 'Tarragon', 'Wild Bergamot'}

>>> annuals = {'Corn', 'Zucchini', 'Sweet Peas', 'Marjoram', 
              'Summer Squash', 'Okra','Shallots', 'Basil', 
              'Cilantro', 'Cumin', 'Sunflower', 'Chervil', 
              'Summer Savory'}

>>> herbs = ['Annatto','Asafetida','Basil','Chervil','Cilantro',
            'Curry Leaf','Fennel','Kaffir Lime','Lavender',
            'Marjoram','Mint','Oregano','Summer Savory', 
            'Tarragon','Wild Bergamot','Wild Celery',
            'Winter Savory']


# Methods will take any iterable as an argument.
>>> perennial_herbs = perennials.intersection(herbs)
{'Annatto', 'Asafetida', 'Curry Leaf', 'Fennel', 'Kaffir Lime',
 'Lavender', 'Mint', 'Oregano', 'Wild Bergamot','Winter Savory'}

# Operators require both groups be sets.
>>> annuals & set(herbs)
 {'Basil', 'Chervil', 'Marjoram', 'Cilantro'}

Symmetrische Differenz von Sets

<set>.symmetric_difference(<other iterable>) gibt ein neues set zurück, das die Elemente enthält, die in <set> ODER in <other> vorkommen, aber nicht in beiden. Die Operatorversion dieser Methode ist <set> ^ <other set>.

>>> plants_1 = {'🌲','🍈','🌵', '🥑','🌴', '🥭'}
>>> plants_2 = ('🌸','🌴', '🌺', '🌲', '🌻', '🌵')


# Methods will take any iterable as an argument.
>>> fruit_and_flowers = plants_1.symmetric_difference(plants_2)
>>> fruit_and_flowers
{'🌸', '🌺', '🍈', '🥑', '🥭','🌻' }


# Operators require both groups be sets.
>>> fruit_and_flowers ^ plants_1
{'🌲',  '🌸', '🌴', '🌵','🌺', '🌻'}

>>> fruit_and_flowers ^ set(plants_2)
{'🥭', '🌴', '🌵', '🍈', '🌲', '🥑'}
Note

Eine symmetrische Differenz von mehr als zwei Sets ergibt ein set, das sowohl die Elemente enthält, die nur in jeweils einem set vorkommen, als auch Elemente, die sich mehr als zwei Sets der Reihe teilen (Details im Wikipedia-Artikel zur symmetrischen Differenz).

Um nur die Elemente zu erhalten, die jeweils nur in einem set der Reihe vorkommen, müssen die Schnittmengen aller 2er-Kombinationen in einem separaten Schritt gesammelt und entfernt werden:

>>> one = {'black pepper','breadcrumbs','celeriac','chickpea flour',
           'flour','lemon','parsley','salt','soy sauce',
           'sunflower oil','water'}

>>> two = {'black pepper','cornstarch','garlic','ginger',
           'lemon juice','lemon zest','salt','soy sauce','sugar',
           'tofu','vegetable oil','vegetable stock','water'}

>>> three = {'black pepper','garlic','lemon juice','mixed herbs',
             'nutritional yeast', 'olive oil','salt','silken tofu',
             'smoked tofu','soy sauce','spaghetti','turmeric'}

>>> four = {'barley malt','bell pepper','cashews','flour',
            'fresh basil','garlic','garlic powder', 'honey',
            'mushrooms','nutritional yeast','olive oil','oregano',
            'red onion', 'red pepper flakes','rosemary','salt',
            'sugar','tomatoes','water','yeast'}

>>> intersections = (one & two | one & three | one & four | 
                     two & three | two & four | three & four)
...
{'black pepper','flour','garlic','lemon juice','nutritional yeast', 
'olive oil','salt','soy sauce', 'sugar','water'}

# The ^ operation will include some of the items in intersections, 
# which means it is not a "clean" symmetric difference - there
# are overlapping members.
>>> (one ^ two ^ three ^ four) & intersections
{'black pepper', 'garlic', 'soy sauce', 'water'}

# Overlapping members need to be removed in a separate step
# when there are more than two sets that need symmetric difference.
>>> (one ^ two ^ three ^ four) - intersections
...
{'barley malt','bell pepper','breadcrumbs', 'cashews','celeriac',
  'chickpea flour','cornstarch','fresh basil', 'garlic powder',
  'ginger','honey','lemon','lemon zest','mixed herbs','mushrooms',
  'oregano','parsley','red onion','red pepper flakes','rosemary',
  'silken tofu','smoked tofu','spaghetti','sunflower oil', 'tofu', 
  'tomatoes','turmeric','vegetable oil','vegetable stock','yeast'}
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab

Lerne Mengen

Das Üben ist gesperrt

Schalte 4 weitere Übungen frei, um Mengen zu üben