Seite 1 von 1

Verschieben von Einträgen inerhalb einer Liste

Verfasst: Freitag 24. Juni 2005, 13:51
von kcon
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

Re: Verschieben von Einträgen inerhalb einer Liste

Verfasst: Freitag 24. Juni 2005, 15:52
von 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.

Verfasst: Freitag 24. Juni 2005, 16:15
von kcon
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

Verfasst: Freitag 24. Juni 2005, 16:42
von kcon
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

Verfasst: Mittwoch 29. Juni 2005, 02:51
von Joghurt
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.

Verfasst: Mittwoch 29. Juni 2005, 09:56
von kcon
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.

Verfasst: Mittwoch 29. Juni 2005, 21:26
von 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.