Verschieben von Einträgen inerhalb einer Liste

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
kcon
User
Beiträge: 4
Registriert: Montag 13. Juni 2005, 17:30
Wohnort: Rhein-Main Gebiet
Kontaktdaten:

Hallo :D
Ich habe vor wenigen Tagen mit dem Programmieren angefange, d.h. ich bin noch blutiger Anfänger.
Ich versuche ein Programm zum verwalten von Todo's zu stricken, komme auch gut voran, aber beim verschieben von Einträgen inerhalb einer Liste hapert es gewaltig! Könnt Ihr mir evtl. weiterhelfen?

Meine Funktion zu diesem Zweck sieht momentan folgendermaßen aus:

Code: Alles auswählen

def movEntry(filename):
	# Die Liste ist in einer Datei abgespeichert
        f = open(filename)
        L = f.readlines()
        f.close()
        for i in range(len(L)):
                print '       %s. %s' % (i+1, L[i].strip())
        print
        while True:
		# getChoice liefert einen Integer
                movEntry = getChoice('Which entry would you like to move?', 'Please type a number: ')
                newEntryPos = getChoice('To which position should the entry be moved?', 'Please type a nu
mber: ')
                posDiff = newEntryPos-movEntry
                if movEntry <= len(L):
                        if newEntryPos <= len(L):
                                if posDiff > 1:
                                        # Copy entry to new position and delete old entry
                                        copy = L.insert(newEntryPos-1, L[movEntry-1])
                                        del L[movEntry]
                                elif posDiff == 1:
                                        # Swap entries
                                        L[newEntryPos-1], L[movEntry-1] = L[movEntry-1], L[newEntryPos-1]
                                else:
                                        print 'Old position and new position are identical.'
                                f = open(filename, 'w')
                                for entry in L:
                                        f.write(entry)
                                f.close()
                                print 'Entry moved.'
                                return False
                        else:
                                print 'You specified an invalid new position, try again!'
                else:
                        print 'You selected an invalid entry, try again!'
Ich hoffe das sind genügend Infos, ich wäre sehr dankbar wenn sich das mal jemand ansieht!

Viele Grüße und vielen Dank im Voraus!
Dennis
Isch könnt' grad an die Deck hibbe!
BlackJack

kcon hat geschrieben:

Code: Alles auswählen

        f.close()
        for i in range(len(L)):
                print '       %s. %s' % (i+1, L[i].strip())
        print
Wenn man ``range(len(x))`` sieht, dann ist das meistens ein Zeichen, das man "C" oder "Java" im Hinterkopf hatte. In Python schreibt man das besser so:

Code: Alles auswählen

for i, line in enumerate(L):
    print '       %4d. %s' % (i+1, line.strip())

Code: Alles auswählen

                                if posDiff > 1:
                                        # Copy entry to new position and delete old entry
                                        copy = L.insert(newEntryPos-1, L[movEntry-1])
                                        del L[movEntry]
Der Name `copy` ist hier überflüssig, weil der Rückgabewert von `list.insert()` nicht eine Liste, sondern `None` ist.

In dem Stück Quelltext liegt auf jeden Fall auch ein Problem; Wenn Du irgendwo etwas einfügst, dann werden alle nachfolgenden Objekte nach hinten verschoben, d.h. es kann passieren dass Du das falsche Objekt aus der Liste entfernst. Nämlich das, welches vor dem zu löschenden liegt, weil ja alle eins weitergerückt sind.

Code: Alles auswählen

                                f = open(filename, 'w')
                                for entry in L:
                                        f.write(entry)
                                f.close()
Das kannst Du analog zum Einlesen mit ``f.writelines(L)`` anstelle der ``for``-Schleife machen.
kcon
User
Beiträge: 4
Registriert: Montag 13. Juni 2005, 17:30
Wohnort: Rhein-Main Gebiet
Kontaktdaten:

Wenn man ``range(len(x))`` sieht, dann ist das meistens ein Zeichen, das man "C" oder "Java" im Hinterkopf hatte. In Python schreibt man das besser so:

Python-Code:

for i, line in enumerate(L):
print ' %4d. %s' % (i+1, line.strip())
Das funktioniert schon mal ganz prima!
Der Name `copy` ist hier überflüssig, weil der Rückgabewert von `list.insert()` nicht eine Liste, sondern `None` ist.
Da habe ich gar nicht drüber nachgedacht, macht aber Sinn ;)
n dem Stück Quelltext liegt auf jeden Fall auch ein Problem; Wenn Du irgendwo etwas einfügst, dann werden alle nachfolgenden Objekte nach hinten verschoben, d.h. es kann passieren dass Du das falsche Objekt aus der Liste entfernst. Nämlich das, welches vor dem zu löschenden liegt, weil ja alle eins weitergerückt sind.
Genau das passiert jedesmal. Ich habe den Eintrag den ich eigentlich verschieben will am Schluss immer 2 mal in der Liste. Aber ich komme nicht dahinter wie ich das umgehen kann. Werde aber weiter rumprobieren!

Dank auch für den Tip mit writelines(), ist definitiv besser :)

Viele Grüße!
Dennis
Isch könnt' grad an die Deck hibbe!
kcon
User
Beiträge: 4
Registriert: Montag 13. Juni 2005, 17:30
Wohnort: Rhein-Main Gebiet
Kontaktdaten:

Mir fällt da gerade noch etwas ein:

Was haltet Ihr davon etwas in der Art zu machen wie ich es für 'posDiff == 1'
schon löse?

Code: Alles auswählen

# Swap entries
 L[newEntryPos-1], L[movEntry-1] = L[movEntry-1], L[newEntryPos-1]
Könnte man nicht eine Funktion schreiben die den zu verschiebenden Eintrag (abhängig davon ob nach oben o. unten verschoben werden soll) mit dem darüber- bzw. darunterliegenden Eintrag vertauscht, und diese Funktion so oft aufrufen wie nötig um den Eintrag an die gewünschte Stelle zu bewegen?
Dann könnte man sich das Theater mit dem Kopieren/Löschen des alten Eintrags sparen.

Ich werde mal versuchen so etwas auf die Beine zu stellen, hat jemand eine Idee wie das aussehen müsste?

Vielen Dank!
Dennis
Isch könnt' grad an die Deck hibbe!
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Ich würde es folgendermaßen machen:

Code: Alles auswählen

# Eintrag mit Index VON nach NACH verschieben
temp = L.pop(VON)
L.insert(NACH,temp)
del temp
Wahrscheinlich geht das ganze auch als Einzeiler:

Code: Alles auswählen

L.insert(NACH,L.pop(VON))
Ich bin mir aber nicht sicher, dass dies garantiert in allen (auch kommenden) Python Versionen funktioniert.
kcon
User
Beiträge: 4
Registriert: Montag 13. Juni 2005, 17:30
Wohnort: Rhein-Main Gebiet
Kontaktdaten:

Danke, Joghurt - das werde ich auch noch mal probieren.

Hatte am WE leider keine Möglichkeit ins Internet zu kommen, dafür aber genug Zeit das Ding zum funzen zu bringen, hier das Ergebnis meiner Mühen:

Code: Alles auswählen

def moveEntry(filename):
        f = open(filename)
        L = f.readlines()
        f.close()
        for i, line in enumerate(L):
                print '       %4d. %s' % (i, line.strip())
        print
        movEntry = getChoice('Which entry would you like to move?', 'Please type a nu
mber: ')
        newEntryPos = getChoice('To which position should the entry be moved?', 'Plea
se type a number: ')
        posDiff = newEntryPos-movEntry
        if posDiff >= 1:
                a = 1
                b = 0
                for i in range(posDiff):
                        L[movEntry+a], L[movEntry+b] = L[movEntry+b], L[movEntry+a]
                        a = a+1
                        b = b+1
        elif posDiff <= -1:
                posDiff = posDiff*(-1)
                a = -1
                b = 0
                for i in range(posDiff):
                        L[movEntry+a], L[movEntry+b] = L[movEntry+b], L[movEntry+a]
                        a = a-1
                        b = b-1
        else:
                print 'Invalid input.'
        f = open(filename, 'w')
        f.writelines(L)
        f.close()
        print 'done.'
Ich vertausche den zu verschiebenden Eintrag sooft wie nötig mit dem darüberliegenden (bzw. darunterliegenden) Eintrag. Das klappt ganz prima :-)

Vielen Dank für Eure Kommentare, hat mir wirklich weitergeholfen!!

Gruß,
Dennis

Edit (Leonidas): Code in Python-Tags gesetzt.
Isch könnt' grad an die Deck hibbe!
BlackJack

Joghurt hat geschrieben:Ich würde es folgendermaßen machen:

Code: Alles auswählen

# Eintrag mit Index VON nach NACH verschieben
temp = L.pop(VON)
L.insert(NACH,temp)
del temp
Wahrscheinlich geht das ganze auch als Einzeiler:

Code: Alles auswählen

L.insert(NACH,L.pop(VON))
Ich bin mir aber nicht sicher, dass dies garantiert in allen (auch kommenden) Python Versionen funktioniert.
Wüsste nicht, warum das in kommenden Versionen nicht mehr funktionieren sollte!?

Das ``del temp`` würde ich aber weglassen. Das bringt wenig bis gar nichts. Der Name `temp` verschwindet am Ende der Funktion sowieso von selbst.
Antworten