Forum: PC-Programmierung Frage zur For-Loop in Python mit zwei Laufvariablen


von Markus W. (dl8mby)


Lesenswert?

Hallo Forum,

wie kann ich in Python zwei Laufvariablen in einer
for Schleife mit jeweils einem Wert aus zwei Listen/Arrays
füllen? Geht das überhaupt?

Den u.g. Code habe ich mal angehängt.

Von Stdin wird ein File mit Parametername und Value gelesen.
(z.B. Druck : 10\n Temp : 30\n usw.). Dieser Zeilenaufbau hat
den Separator ":" und ist eigentlich sehr simpel.

Nun lese ich den Parameternamen ins Array P[] und den Veluewert
ins Array V[] ein. Das funktioniert soweit.

Danach möchte ich nach dem Einlesen der Datei ein Wertepaar
"Parametername,Vaulewert" in einer Schleife ausgeben,
wobei ich die for Schleife wie folgt angebe.

import sys

P=[] # Parameter
V=[] # Value

for line in sys.stdin:
        (param,value)=line.split(': ')
        P.append(param)
        V.append(value)

i=0
for (p,v) in (P[i],V[i]):  <== Mein Problem
        print(p,v)
        i=i+1

Traceback (most recent call last):
    for (p,v) in (P[i],V[i]):
ValueError: too many values to unpack (expected 2)

Wahrscheinlich wird das Tupel (P[i],V[i]) nur einmal
bei i=0 ausgewertet oder wo liegt das Problem.

Danke für Eure Hilfe.

Markus

von Sheeva P. (sheevaplug)


Lesenswert?

Markus W. schrieb:
> wie kann ich in Python zwei Laufvariablen in einer
> for Schleife mit jeweils einem Wert aus zwei Listen/Arrays
> füllen? Geht das überhaupt?

Nicht daß ich wüßte. Was ginge, wäre der Zugriff über einen klassischen 
Schleifenzähler:
1
for i in range(len(V)):
2
    print(V[i], P[i])

> Von Stdin wird ein File mit Parametername und Value gelesen.
> (z.B. Druck : 10\n Temp : 30\n usw.). Dieser Zeilenaufbau hat
> den Separator ":" und ist eigentlich sehr simpel.
>
> Nun lese ich den Parameternamen ins Array P[] und den Veluewert
> ins Array V[] ein. Das funktioniert soweit.

Nimm' doch eine passende Datenstruktur dafür -- entweder eine Liste von 
Tupeln oder ein OrderedDict aus dem Paket collections.

von anaconda (Gast)


Lesenswert?

for (p,v) in zip(P,V):

von Markus W. (dl8mby)


Lesenswert?

Hallo,

Danke euch beiden, das ging ja flott!

Habe die Variante von anaconda genommen.

>cat tmp.txt
P1 : 1
P2 : 2
P3 : 3

>cat ./tmp.txt | ./plot_stat.py
P1  1
P2  2
P3  3

Gruß
Markus

von imonbln (Gast)


Lesenswert?

Sheeva P. schrieb:
> Nimm' doch eine passende Datenstruktur dafür -- entweder eine Liste von
> Tupeln oder ein OrderedDict aus dem Paket collections.

das ist eigentlich der Wichtige Hinweiss, du solltest deinen parameter 
nicht nur über den Index an den Value binden, der Python-way sowas zu 
machen wäre ein Tuple, Dict oder OrderedDict, um diese werte aneinader 
zu binden.
Je nach dem was du dannch machst und weitern requierments ist einer 
dieser Datentypen zu wählen.
1
parameter = dict()
2
for line in sys.stdin:
3
    k , v = line.split(': ')
4
    parameter.setdefault(k, v) 
5
6
7
for key in parameter.keys():
8
   print(k, parameter[key])

wäre zum bespiel die lösung mit dictornary, wobei die wiedergabe bewust 
nicht mit items gemacht wurde um dir zu demonstieren das dein parameter 
in dem Fall der Key ist wo mit du den wert erhälst.

von Sheeva P. (sheevaplug)


Lesenswert?

Markus W. schrieb:
> Danke euch beiden, das ging ja flott!
>
> Habe die Variante von anaconda genommen.

Keine gute Idee. Das kopiert die bereits gelesenen Daten in genau die 
Liste von Tupeln, in Du gleich die Originaldaten hättest einlesen 
können. Kostet temporär das doppelte an Speicher und natürlich die 
Kopieroperation.

>>cat tmp.txt
> P1 : 1
> P2 : 2
> P3 : 3
>
>>cat ./tmp.txt | ./plot_stat.py
> P1  1
> P2  2
> P3  3

Warum liest Du denn nicht gleich aus der Datei?

von Markus W. (dl8mby)


Lesenswert?

Hallo Sheeva,
und  imonbln,

wie Ihr an meiner Fragestellung ja gesehen habt,
bin ich noch kein Python Experte.

Der Grund, warum ich es so mache ist einfach noch der
Mangel an Erfahrung, was Python angeht.

Der cat und die Pipe in meinem Beispiel zielte nur darauf
ab Euch zu demonstrieren, was ich für einen Input bekomme.

Ich bekomme aus einer Datei die genannten Wertepaare,
wobei nicht alle Parameter für mich von Interesse sind.

Die die mich interessieren möchte ich herausfiltern und
entsprechend weiter verarbeiten (soll ein 2D xy-Plot werden).

Den Vorschlag von "imonbln" mit dem Dictionary werde ich mir
näher ansehen und umzusetzen versuchen.

parameter = dict()
for line in sys.stdin:
    k , v = line.split(': ')
    parameter.setdefault(k, v)


for key in parameter.keys():
   print(k, parameter[key])

Vom Aufbau ähnelt es ja Perl, wo ich mehr Erfahrung habe.
Ich wollte es aber gezielt mit Python realisieren, um auch
in dieser Skrtiptsprache etwas Übung zu bekommen.

Danke für Eure Hilfe. Wenn es wieder irgendwo hackt, melde
ich mich wieder.

Markus

von Sheeva P. (sheevaplug)


Lesenswert?

Markus W. schrieb:
> Der cat und die Pipe in meinem Beispiel zielte nur darauf
> ab Euch zu demonstrieren, was ich für einen Input bekomme.

Ok, dann zeig' ich Dir mal eine Lösung:
1
from argparse import ArgumentParser
2
from collections import OrderedDict
3
import matplotlib.pyplot as plt
4
5
if __name__ == '__main__':
6
    # Übergabe des Dateinamens:
7
    parser = ArgumentParser(description='Daten aus Datei lesen')
8
    parser.add_argument('filename', type=str, help='Dateiname')
9
    args = parser.parse_args()
10
11
    # Daten lesen
12
    data = OrderedDict()
13
    with open(args.filename, 'r') as ifh:
14
        for line in ifh:
15
            k, v = map(str.strip, line.split(':'))
16
            data[int(k)] = float(v)
17
18
    # ...zB plotten
19
    plt.plot(data.keys(), data.values())
20
    plt.show()

Bitte beachte, daß ich die eingelesenen Strings dabei gleich auch in 
int() und float()-Werte konvertiere; hier sind natürlich auch andere 
Datentypen wie datetime.datetime (hierzu bitte dateutils.parser.parse() 
anschauen) möglich. Deine Filter kannst Du, wahlweise vor oder nach der 
Zeile "k, v =...", oder auch nach dem kompletten Einlesen der Daten 
einbauen.

In Deinem Beispiel kannst Du die Daten allerdings allerdings auch in 
zwei Listen speichern, weil Du die zum Plotten mit Matplotlib eh 
brauchst. Ich erzeuge die mit den Methoden keys() und values() des 
OrderedDict.

> Den Vorschlag von "imonbln" mit dem Dictionary werde ich mir
> näher ansehen und umzusetzen versuchen.

Bitte bedenke dabei, daß so ein Python-Dictionary (ähnlich wie ein 
Perl-Hash und im Gegensatz etwa zu PHP) keine definierte Reihenfolge der 
Keys kennt. Wenn Du die Reihenfolge der Schlüssel behalten willst, 
brauchst Du deswegen das OrderedDict aus den collections.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Sheeva P. schrieb:
> Markus W. schrieb:
>> Danke euch beiden, das ging ja flott!
>>
>> Habe die Variante von anaconda genommen.
>
> Keine gute Idee. Das kopiert die bereits gelesenen Daten in genau die
> Liste von Tupeln, in Du gleich die Originaldaten hättest einlesen
> können. Kostet temporär das doppelte an Speicher und natürlich die
> Kopieroperation.

Im von Markus verwendeten Python 3 erzeugt zip() keine Liste, sondern
liefert einen Iterator, der genau den von dir beschriebenen Nachteil
vermeidet. Trotzdem hast du natürlich recht, dass man die Daten schon
beim Einlesen in eine passende Datenstruktur packen sollte. Ob man für
diese Datenstruktur besser eine Liste von Tupeln oder ein (ordered)
Dictionary wählt, hängt davon ab, wie ein mehrfaches Auftreten des
gleichen Parameternamens im Eingabedatenstrom behandelt werden soll.

von Markus W. (dl8mby)


Lesenswert?

Hallo Sheeva,
hallo Yalu,
und natürlich mc-Forumsleser.

Danke für die detaillierten Vorschläge zu meinem Problem.

In meinem konkreten Fall sieht es so aus.
Ich erzeuge mir mittels eines bash Skriptes die beschriebenen
Wertepaare aus Abfragen an eine sqlite Datenbank.
Diese Abfragen liefern für bestimmte aufsteigende Zeitintervalle
bestimmte Vorkommen von Ereignissen. Diese sollen gezählt werden
(macht die DBk) und dann in Form eines Graphen visualisiert werden.
Auf dem Quellsystem, wo die DBk läuft, kann ich kein Python an-
wenden, deshalb bash. Am Zielrechner will ich die Daten entsprechend
für eine Monatsstatistik aufbereiten. Bis dato wurde dies von
meinem Kollegen via Excel gemacht. Um ihn diesen Arbeitsaufwand
zu ersparen, will ich diese Aufgabe nun automatisieren, wie es
eigentlich sinnvoll ist.
Gleichzeitig wollte ich bei der Gelegenheit etwas in Python machen,
da der Umfang noch recht überschaubar ist.
Die Keys können mehrfach auftreten, wobei es von ihnen mehrere
Typen gibt. Diese muss ich zusammenfassen, ihre Häufigkeit
ermitteln und auf der Zeitachse entsprechend z.B. als Balken
darstellen. Es soll so was wie ein Histogramm werden, das die
Häufigkeit der Ereignisse auf der Zeitachse darstellt abhängig
von bestimmten Initial-Zeitpunkten.

Werde morgen entsprechend weiter machen und hoffe, dass alles so
klappt, wie ich es mir vorgestellt habe.

Danke nochmals für die ausführlichen Hinweise.

Schönen Abend und bis zum nächsten Mal.

Markus

von Ralf B. (Firma: Scorptech) (mad_scorp)


Lesenswert?

Markus W. schrieb:
> Die Keys können mehrfach auftreten, wobei es von ihnen mehrere
> Typen gibt. Diese muss ich zusammenfassen, ihre Häufigkeit
> ermitteln und auf der Zeitachse entsprechend z.B. als Balken
> darstellen. Es soll so was wie ein Histogramm werden, das die
> Häufigkeit der Ereignisse auf der Zeitachse darstellt abhängig
> von bestimmten Initial-Zeitpunkten.

Das von Sheeva verwendete matplotlib kann im übrigen auch gleich 
Histogramme out of the box. Diese Bibliothek war ursprünglich mal für 
Leute gedacht, die sich mit Matlab auskennen und kann daher auch eine 
Menge Dinge für die man sonst einen Riesenaufwand treiben muss.

Edit: Link zur matplotlib webseite https://matplotlib.org/

: Bearbeitet durch User
von Markus W. (dl8mby)


Lesenswert?

Hallo Forum,
hallo anaconda,

Habe mir gestern die buildin zip Funktion in Python angeschaut.
und bei dieser Gelegenheit die vielen anderen buildin Funktionen
gelistet bekommen. Vieles ist selbsterklärend aber manches davon
muss man erst selbst verinnerlichen bei dieser Vielfalt.



Return Value from zip()

 The zip() function returns an iterator of tuples based on the iterable 
object.

 If no parameters are passed, zip() returns an empty iterator

 If a single iterable is passed, zip() returns an iterator of 1-tuples.
 Meaning, the number of elements in each tuple is 1.

 If multiple iterables are passed, ith tuple contains ith Suppose,
 two iterables are passed; one iterable containing 3 and other
 containing 5 elements. Then, the returned iterator has 3 tuples.
 It's because iterator stops when shortest iterable is exhaused.

Der dritte Passus zur zip-Funktion bestätigt , dass man sogar
mehrdimensionales "zippen" bewerkstelligen kann, also sowas wie

for (x,y,z...) in zip(X,Y,Z,...):

Wobei die kürzeste Liste die Anzahl der Iterationen festlegt.
In meinem Fall haben diese Listen ja die gleiche Länge.
Bin begeistert von dieser Möglichkeit.


Schwierigkeit für mich am Anfang besteht darin die für eine Problem 
nützlichen
Bibliotheken zu finden und die entsprechenden Funktionen darin, um nicht 
das
Rad wieder neu zu erfinden.
Bis ich da den Überblick habe, wird es wohl noch etwas dauern.

Die matplotlib Docs schaue ich mir gerade an und die zugehörigen
Beispiele in der Gallery unter

https://matplotlib.org/gallery/index.html

Danke nochmals für diesen Hinweis.

Markus

von der Oberleerer (Gast)


Lesenswert?

> Schwierigkeit für mich am Anfang besteht darin die für eine Problem
> nützlichen
> Bibliotheken zu finden und die entsprechenden Funktionen darin, um nicht
> das
> Rad wieder neu zu erfinden.
> Bis ich da den Überblick habe, wird es wohl noch etwas dauern.
>

Das is nun mal immer so.

Dagegen hilft z.B. erst mal wissen was/wohin man will in der 
Problemlösung entspr. benötigt man eine Basis in Grundlagen wie z.B 
Mathe/Menenlehre/Lineaalgebra/Funktionen/Graphen/Algorithmen/Datenstrukt 
uren/...  und die da üblichen Fachbegriffe. Damit kann man -ggfs. 
übersetzt auf english- die libs abklopfen.
Alternative: Doku zu den libs auswändig lernen und hoffen im passenden 
Moment vor gestelltem Problem den Glückstreffer abrufen zu können.

Das Rad neu erfinden hilft nicht zuletzt das Verständnis für 
Problemstellung und (lib-)Implementation zu vertiefen, man kann so auch 
bereits erfundene Räder besser bewerten denn die haben nicht 
bedingungslos alle und immer passende Eigenschaften :-) Das gehört hin 
und wider dazu.

von Markus W. (dl8mby)


Lesenswert?

So ist es.

Von meiner Seite ist dem Nichts mehr hinzuzufügen ;-)

Markus

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.