Listenbearbeitung

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
Gerhardus
User
Beiträge: 42
Registriert: Dienstag 31. Dezember 2013, 01:59

Hallo,
ich hätte wieder mal eine Frage an die Experten.
Ich habe in meinem fertigen Programm eine Funktion, welche mir aus einer sortierten Liste
die Platzziffern hinzufügt und zwar so das bei gleicher Punkteanzahl die gleicher Platzziffer bleibt und der nächste Platz
überspringen wird. Meine Lösung funktioniert tadellos, es würde mich aber interessieren, ob es eine bessere Lösung dafür gibt?
Ich habe mich mit enumerate und mit generatoren ein wenig eingelesen, um ev. mit einer Schleife auszukommen aber es ist nichts dabei rausgekommen.
Gruß Gerhardus.

Code: Alles auswählen

def platz(ra_liste):
    for i in range(len(ra_liste)):
        ra_liste[i].insert(0,i+1)
    last_rang=ra_liste[0][0]
    last_cp=ra_liste[0][2]
    for i in range(len(ra_liste)):
        if ra_liste[i][2]==last_cp:
            ra_liste[i][0]=last_rang
        last_rang=ra_liste[i][0]
        last_cp=ra_liste[i][2]
    return ra_liste

if __name__ == '__main__':
    ra_liste=['Maier Susi', 973, 'A'], ['Mustermann Max', 600, 'B'],\
      ['Knoll Markus', 600, 'B'], ['Müller Thomas', 600, 1411],\
      ['Schmidt Hilde', 301,'A'], ['Messi Max',500,'C']
    new_li=platz(ra_liste)
    for i in new_li: print(i)
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Hallo,

du hast dort keine Liste, sondern ein Tupel mit Listen.
Dateitypen haben im Variablennamen nichts zu suchen, also das *liste kann weg. Auch sollten Variablen eindeutige Namen haben und keine Abkürzungen wie "ra", da es dann schwerer wird das Programm nachzuvollziehen.
Man iteriert nicht über eine Liste mit dem Index, sondern direkt über die Elemente der Liste, also statt:

Code: Alles auswählen

for i in range(len(ra_liste)):
    print(ra_liste[i])
so:

Code: Alles auswählen

for element in ra_liste:
    print(element)
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Benutze keine Abkürzungen.
Tuple sind dazu da, verschiedenartige Dinge zusammenzufassen (wie z.B. Name, Punkte, etc.), Listen dagegen, um gleichartige Elemente zu speichern. Bei ra_liste ist es genau falsch herum.
new_li ist exakt das selbe Objekt wie ra_liste, daher ist es keine gute Idee, einer Funktion einen Parameter zu übergeben, der auch gleichzeitig Rückgabewert ist, das verwirrt nur. Am besten erzeugt man auch immer neue Listen, statt welche zu verändern.
`i` ist ein besonders schlechter Name für eine Liste.
Alles unter if __name__ gehört in eine Funktion main.

Code: Alles auswählen

def platz(teilnehmer):
    raenge = []
    vorherige_punkte = vorheriger_platz = None
    for platz, element in enumerate(teilnehmer, 1):
        punkte = element[1]
        if vorherige_punkte == punkte:
            platz = vorheriger_platz
        raenge.append((platz,) + element)
        vorherige_punkte = punkte
        vorheriger_platz = platz
    return raenge

def main():
    teilnehmer = [
        ('Maier Susi', 973, 'A'),
        ('Mustermann Max', 600, 'B'),
        ('Knoll Markus', 600, 'B'),
        ('Müller Thomas', 600, 1411),
        ('Schmidt Hilde', 301,'A'),
        ('Messi Max',500,'C'),
    ]
    raenge = platz(teilnehmer)
    for rang in raenge:
        print(rang)

if __name__ == '__main__':
    main()
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

@Sirius3:

Wenn in der Liste Teilnehmer die Reihenfolge aber nicht entsprechend der Rangfolge ist funktioniert das nicht. Und es werden Plätze übersprungen.
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Jankie: Vorgabe von Gerhardus war, dass die Liste bereits sortiert ist. Ich denke Sirius3 ist davon ausgegangen das die Sortierung nach Punkten erfolgte. Wäre ich auch von ausgegangen.

Ist die Frage wie man in der Funktion damit umgeht. Gar nix machen, nach dem Prinzip „garbage in → garbage out“. Dann sollte man das sortiert nach Punkten aber am besten dokumentieren, damit es keinen überrascht wenn man Unsinn bekommt, falls diese Vorbedingung nicht erfüllt ist.

Oder man testet ob die Punkte aufsteigend sortiert sind während man die Ränge vergibt und bricht mit einer Ausnahme ab falls das nicht erfüllt ist.

Oder man packt das sortieren auch mit in die Funktion, dann ist man sicher das man mit einer sortierten Liste arbeitet. Ich würde wahrscheinlich diese Option wählen. Falls die Liste schon sortiert rein kommt ist das von CPython verwendete ”Timsort” nicht wesentlich ineffizienter als die Sortierung zu testen. Oder anders herum formuliert: ”Timsort” ist effizient bei bereits sortierten Listen.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Ich sollte die Aufgabenstellung genauer lesen..... Sorry für das Missverständnis.
Gerhardus
User
Beiträge: 42
Registriert: Dienstag 31. Dezember 2013, 01:59

Danke uch für die raschen Antworten.
Zu meiner Entschuldigung muss ich erwähnen, dass ich das aus meinem fertigen Programm schnell hearauskopiert und
lediglich die Personennamen geändert habe und in Idle getestet habe.
Das ich statt Rangliste nur ra_liste ist meiner Schreibfaulheit gestundet, ausserdem bin ich als Hobbyist beim Code schreiben nicht davon ausgegangen
dass ausser mir jemand den Code lesen wird, jedoch gelobe diesbezüglichich Besserung.
Das List-Objekt ist deshalb entstanden weil die Daten aus einer Access DB kommen und um gewisse Änderungen vorzunehmen, musste ich Tuple zu List konvertieren.
Mit dem Iterieren über die Elemente bin ich auf Grund der unterschiedlichen Typen nich auf klar gekommen, deshalb mit index.
Danke Sirius für dein Codebeispiel, welches mich motiviert, mir daran ein Beispiel zu nehmen.
Die Reihenfolge ist sortiert.
Danke nochmals und

Gruss Gerhardus
Gerhardus
User
Beiträge: 42
Registriert: Dienstag 31. Dezember 2013, 01:59

@Sirius3

Hallo ,

bei Verwendung deines Codebeispieles bin ich auf folgendes Problem gestossen.
In meinen ursprunglichen Programm kommt die Teilnehmerliste aus einer Access DB,
welche mit pypyodbc Connection und mit fetchall die Rangliste liefert. Diese Liste
besteht aus den Elementen folgendes Types:

Code: Alles auswählen

 <class 'pypyodbc.TupleRow.<locals>.Row'>
dies wird von von deiner Def Platz als Tuple in

Code: Alles auswählen

raenge.append((platz,) + element)
akzeptiert.

Ich habe allerdings in meiner überarbeiteten 2. Version eine Verbindung über sqlalchemy (von black_jack empfohlen)
hergestellt, Diese liefert mir aus fetchall folgendes object:

Code: Alles auswählen

<class 'sqlalchemy.engine.result.RowProxy'>
welches zu einem Error führt:

Code: Alles auswählen

raenge.append((platz,) + element)
TypeError: can only concatenate tuple (not "RowProxy") to tuple
Mit

Code: Alles auswählen

 rangliste=[list(x) for x in rangliste] 
habe ich ursprunglich in meiner Def platz diese zu einer Liste erstellt, was funktionierte,
aber die unschönen Typen erzeugte.
Da ich aber gerne mit enumerate wie vorgeschlagen arbeiten würde, wäre meine Frage ob es hiefür eine
Lösung gibt. (RowProxy to tuple)?
Danke und
Gruß Gerhardus
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Gerhardus: Ich würde hier einfach mal in Frage stellen strukturierte Informationen in so etwas wie Listen, oder auch Tupeln zu halten. Beziehungsweise wenn Tupel, dann nicht mit zu vielen Elementen. Tupel mit zwei Elementen, Platznummer und Teilnehmer zum Beispiel.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Gerhardus
User
Beiträge: 42
Registriert: Dienstag 31. Dezember 2013, 01:59

@_blackjack_
Was wäre denn die Alternative?
Mein Problem hat sich erübrigt, da mit:

Code: Alles auswählen

rangliste=[tuple(x) for x in rangliste]
alles funktioniert.

Gerhardus
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Du hast schon komplexe Daten. Die zu entpacken führt nur dazu, dass Information verloren geht. Statt dessen sollte die Ranglistenfunktion keine Tupel erweitern, sondern nur 2Tupel (Rang, Teilnehmer) zurückliefern.
Antworten