Frage zu for-schleifen und Listen

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
Malinka
User
Beiträge: 18
Registriert: Donnerstag 29. August 2013, 15:53

Ich bin noch nicht so fit in Python und hoffe, dass ihr mir bei folgendem Problem helfen könnt:

Ich möchte mithilfe einer for-Schleife verschiedene Listen erzeugen. Mit jedem Durchlauf erzeuge ich also eine Liste. Wie kann ich nun anschließend auf einzelne erzeugte Listen zugreifen, um die Listen aus allen Durchläufen miteinander zu vergleichen?

Ich hoffe, meine Frage ist verständlich, wenn nicht, bitte ich euch, mir zu sagen, was unverständlich ist :wink:
BlackJack

@Malinka: Du könntest die Listen zum Beispiel in einer Liste speichern.
Malinka
User
Beiträge: 18
Registriert: Donnerstag 29. August 2013, 15:53

Und wie mache ich das?
Ich hatte dazu jetzt die Idee, außerhalb der for-Schleife eine neue Liste anzulegen, die den Inhalt der for-Schleife enthält, aber irgendwie scheint das wohl falsch zu sein.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Malinka hat geschrieben:Ich hatte dazu jetzt die Idee, außerhalb der for-Schleife eine neue Liste anzulegen, die den Inhalt der for-Schleife enthält, aber irgendwie scheint das wohl falsch zu sein.
Wahrscheinlich hast du es nur falsch umgesetzt.

Code: Alles auswählen

>>> import random
>>> datapool = []
>>> for _ in range(3):
	data = [random.randint(1, 10), random.randint(1, 5), random.randint(1, 3)]
	datapool.append(data)

>>> print datapool
[[6, 5, 3], [4, 5, 2], [8, 5, 3]]
>>> for entry in datapool:
	print entry

[6, 5, 3]
[4, 5, 2]
[8, 5, 3]
datapool ist die Liste, die die anderen Listen aufnimmt. Innerhalb der Schleife wird jeweils eine neue Liste mit Namen data erstellt und der Liste datapool als Element zugefügt.

Die Ausgabe nach der Schleife zeigt das Ergebnis.
Zuletzt geändert von /me am Donnerstag 29. August 2013, 16:25, insgesamt 1-mal geändert.
BlackJack

@Malinka: Du legst eine leere Liste an, und jede erzeugte Liste in der ``for``-Schleife hängst Du an diese Liste an.

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from pprint import pprint
from random import randint


def main():
    result = list()
    for _ in xrange(10):
        result.append([randint(1, 6) for _ in xrange(5)])
    pprint(result)


if __name__ == '__main__':
    main()
Ergebnis:

Code: Alles auswählen

[[6, 2, 2, 6, 1],
 [6, 4, 2, 6, 6],
 [2, 1, 3, 6, 5],
 [1, 4, 1, 5, 4],
 [2, 2, 4, 2, 2],
 [2, 6, 3, 5, 5],
 [4, 3, 1, 1, 2],
 [5, 1, 5, 5, 3],
 [5, 1, 3, 3, 6],
 [2, 1, 5, 4, 4]]
Wobei man die äussere ``for``-Schleife hier wahrscheinlich auch durch eine „list comprehension” ersetzen könnte, ohne dass es zu unverständlich wird.
Malinka
User
Beiträge: 18
Registriert: Donnerstag 29. August 2013, 15:53

Ohjeee, ich glaube, ich muss mir noch einiges an Grundlagen anschauen. :? :shock:

Gibt es vielleicht auch eine Version ohne Module zu importieren? :wink:

Auf jeden Fall danke schonmal.
Malinka
User
Beiträge: 18
Registriert: Donnerstag 29. August 2013, 15:53

So, ich habe jetzt einfach nur folgendes gemacht:

1. Neue Liste angelegt:
liste1 = []

2. Ans Ende der for-Schleife:
liste1.append(liste)

Das sollte doch reichen, oder? Sieht auf jeden Fall ganz gut aus :wink:
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Malinka hat geschrieben:Ohjeee, ich glaube, ich muss mir noch einiges an Grundlagen anschauen. :? :shock:

Gibt es vielleicht auch eine Version ohne Module zu importieren? :wink:
random bzw. pprint waren ja nur zum Erzeugen der Daten bzw. für eine formatierte Ausgabe. Zudem ist das Importieren von Modulen nichts Schlimmes.

Du solltest auf jeden Fall das Tutorial für Python 2 oder das Tutorial für Python 3 durcharbeiten, je nachdem welche Version du einsetzt.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Malinka hat geschrieben:1. Neue Liste angelegt:
liste1 = []

2. Ans Ende der for-Schleife:
liste1.append(liste)

Das sollte doch reichen, oder? Sieht auf jeden Fall ganz gut aus :wink:
Du solltest dir nur abgewöhnen den Typ der Variablen in deren Namen mit aufzunehmen. Das bringt in den meisten Fällen keine Vorteile. Das kann im Gegenteil sogar von Nachteil sein wenn du mal auf eine andere Datenstruktur umstellst und der Name dann auf einmal irreführend ist.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ergänzend zu /me: Du solltest Dir auch abgewöhnen, Namen mit Indizes / Nummern zu versehen! Was sagt Dir denn ``liste1``? Dass sie zuerst an etwas gebunden wird? Dass sie irgend wie anders ist als nur ``liste``?

Im Regelfall macht man etwas falsch, wenn man Namen nummeriert! Entweder gibt es einfach einen treffenderen (s. z.B. ``datapool``, ``result`` - wenn es sich denn um ein Ergbnis an sich handelt), oder aber man hat lauter separate Namen a la ``a1``, ``a2``, ..., ``an`` - dann will man stattdessen eine *äußere* Datenstruktur benutzen, wie Du es ja anstrebst.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Malinka
User
Beiträge: 18
Registriert: Donnerstag 29. August 2013, 15:53

Okay, mit den Bezeichnungen habt ihr absolut recht. :wink:

Jetzt habe ich noch eine anderen Frage. (noch mit den unübersichtlichen Bezeichnungen)

Ich habe also nun eine Liste, die eine bestimmte Anzahl Listen (in meinem Fall jetzt 4) enthält. Nun möchte ich alle gemeinsamen Wörter, die also in jeder "Unterliste" vorkommen, wieder einer neuen Liste hinzufügen. Das muss ja irgendwie einfacher gehen, als nach meiner Variante. Ich muss vermutlich irgendwie eine range festlegen, damit er jeden Listenindex nach dem Vorkommen des Wortes überprüft. Ich bekomme es aber nicht hin

Code: Alles auswählen

liste2 = []
for wort in liste1[0]:
        if wort in liste1[1]:
            if wort in liste1[2]:
                 if wort in liste1[3]
                      liste2.append(wort)
EDIT: Der Code soll also variabler werden, unabhängig von der Zahl der Listen.
BlackJack

@Malinka: Dazu solltest Du Dir mal den Datentyp `set` anschauen. Damit kann man deutlich einfacher und auch effizienter Schnittmengen bilden.

Edit: Und es geht auch ohne das man explizit Schleifen schreiben muss:

Code: Alles auswählen

from operator import and_

# ...

common_words = reduce(and_, word_sets)
Malinka
User
Beiträge: 18
Registriert: Donnerstag 29. August 2013, 15:53

Okay, mit das mit set habe ich grundsätzlich verstanden. Aber wie lege ich in der for-schleife die range fest? Ich muss ja, um die Schnittmenge zu bilden, z.B. "set1 & set2 & set3 & set4" durchführen. Wie ich anfange, weiß ich, schätze ich:

Code: Alles auswählen

for i in range(len(liste):
    schnittmenge = set(wortliste[i])
# ?????
:
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Hui... Du hast - wie fast jeder Anfänger - mal wieder den Anti-Pattern schlecht hin eingebaut:

Code: Alles auswählen

for i in range(len(liste):
    # zugriff auf Elemente via Index: liste[i]
Vergiss sofort wieder, dass so etwas prinzipiell funktioniert :!:

In Python iteriert man *direkt* über Elemente einer Liste (allgemein eines Iterables), wenn man sich für diese interessiert:

Code: Alles auswählen

for words in liste:
    # words ist eine Sub-Liste in Deinem Falle
Und benenne endlich diese ``liste`` um!

Du kannst aus Deiner verschachtelten Listen-Struktur via ``map`` eine Liste von Sets machen:

Code: Alles auswählen

word_sets = map(set, liste)
Danach hat Dir BlackJack ja schon gezeigt, wie man mittels ``reduce`` einfach den Schnitt über alle Mengen bilden kann.

Du kannst Dir natürlich auch sofort Sets von Wörtern bauen - es sei denn, es gibt zu Beginn einen guten Grund dafür, diese erst einmal in einer Liste zu lassen.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Zuerst solltest du dir `for i in range(len(list))` abgewoehnen, in Python kann man direkt ueber die Elemente iterieren und das will man meist auch. Sollte zusaetzlich noch der Index noetig sein, gibt es `enumerate`.

Hier zwei Ansaetze fuer die Schnittmenge:

Code: Alles auswählen

In [20]: words = [['a', 'b', 'c'], ['a', 'd', 'e'], ['f', 'a', 'g']]

In [21]: word_intersection = reduce(set.intersection, map(set, words))

In [22]: word_intersection
Out[22]: set(['a'])
Oder "manueller"

Code: Alles auswählen

In [23]: word_intersection = set(words[0])

In [24]: for sub_words in words:
   ....:     word_intersection.intersection_update(set(sub_words))
   ....:     

In [25]: word_intersection
Out[25]: set(['a'])
Dein Ansatz funktioniert nicht, weil du immer wieder `schnittmenge` ueberschreibst, statt sie zu aktualisieren.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@cofi: In Deinem zweiten Ansatz könnte man beim zweiten Element in der for-Schleife anfangen ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Malinka
User
Beiträge: 18
Registriert: Donnerstag 29. August 2013, 15:53

Vielen vielen Dank für die Hilfestellungen. Ich werde mich da morgen weiter mit auseinandersetzen, da mein Kopf langsam ziemlich dröhnt. :P
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ja, und man koennte einen Iterator benutzen und das erste Set mit `next` initialisieren .. aber ich wollte es einfach halten ;)
Malinka
User
Beiträge: 18
Registriert: Donnerstag 29. August 2013, 15:53

Okay, habe doch nicht die Finger davonlassen können.
@ cofi Habe jetzt eher deinen konservativeren Vorschlag genommen, da der doch für mich am besten nachvollziehbar ist und es so nach meinem Geschmack angepasst:

Code: Alles auswählen

vergleichsliste = set(wortliste[0])
    for worte in wortliste:
        #Ein Set der Worte aus der ersten "Sub-Liste" wird mit den Sets aus allen "Sub-Listen" verglichen und die Schnittmenge gebildet
        vergleichsliste &= set(worte)
Habe ich die Funktionsweise jetzt richtig verstanden (siehe Kommentar)?

Wahrscheinlich lacht ihr jetzt, aber ich weiß nicht, warum in meinem Code aus &= hier &= gemacht wird...
BlackJack

@Malinka: Das liegt am Forum. Aber nicht nur deswegen solltes Du lieber die Methode verwenden. Da brauchst Du erstens die `worte` nicht in ein `set` umwandeln und zweitens wird nur `set` verwendet das aktualisiert wird, statt in jedem Schleifendurchlauf ein neues `set` mit einem Zwischenergebnis zu erstellen. Und lesbarer ist es auch, weil man bei einem Methodennamen leichter in der Dokumentation suchen kann als bei einem Operator.
Antworten