Listen kopieren

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
Nikolas
User
Beiträge: 102
Registriert: Dienstag 25. Dezember 2007, 22:53
Wohnort: Freiburg im Breisgau

Ja ich weiss, klingt genauso wie der Thread darunter, nur habe ich den Fehler dort nicht begangen :)

Für die Uni schreibe ich mir gerade ein kleines Programm, das folgendes macht:
Ich habe eine Wahl mit W Wählern und K Kandidaten, wobei jeder Wähler eine Präferenz
liste abgibt, also nicht nur einen Kandidaten wählt, sondern alle in eine Reihenfolge
bringt.
Dann habe ich vier verschiedene Auszählungsverfahren und will schauen, wie viele unterschiedliche
Sieger ich finden kann. In der While-schleife erzeuge ich ein zufälliges Wahrergebniss
und speichere dann in erg die Ergebnisse der einzelnen Verfahren. relativ und borda
lesen nur, wobei Coombs und Preference das Wahlergebniss weiterverarbeiten in dem
manche Kandidaten gestrichen werden. Deswegen wollte ich jeder Funktion eine Kopier
des erzeugten Wahlergebnisses übergeben, was ich über die Slice-Kopie gemacht habe.
Wenn ich aber coombs(copyd) aufrufe, und mich danach copyc anzeigen lasse,
steht in Copyc nicht das ursprüngiche Wahlergebniss, sondern das, was Coombs vom Wahl
ergebniss übrig lässt. (am besten einfach mal ausführen). Es sieht also so aus, als ob
copyd und copyc das gleiche Objekt sind. Wobei
print (copyd is copyc)
print copyd == copyc
False und True ausgeben, was auch so zu erwarten ist.

Wenn ich aber direkt:
L=range(3)
K=L[:]
K.delete(2)
ausführe, besteht L immer noch aus drei Elementen.

Wie komme ich also an eine richtige Kopie? oder besser: wo mache ich meinen Fehler?

Code: Alles auswählen

import random
from Tkinter import IntVar
# Anzahl Kandidaten : 
K=5
# Anzahl Wähler: 
W=8

def neueWahl():
    erg = []
    for i in range(W):
        a = range(K)
        random.shuffle(a)
        erg.append(a)
    return erg

# vorne in der Liste steht der beste Kandidat!

def relativ(Wahl):
    e=[0]*K
    for liste in Wahl:
        e[liste[0]]+=1
        
    return e.index(max(e))

def borda(Wahl):
    e=[0]*K
    for liste in Wahl:
        for i in range(K):
            e[liste[i]]+=W-i-1 #+1 damit der erste Kandidat W-1
                               # Punkte bekommt
    return e.index(max(e))

def MostLastPlaces(Wahl):
    e=[0]*K
    for liste in Wahl:
        e[liste[-1]]+=1

    return e.index(max(e))
    

def LeastFirstPlaces(Wahl):
    e=[0]*K
    for liste in Wahl:
        e[liste[0]]+=1

    minimum = W
    pos = 0
    for i in range(K):
        if i not in Wahl[0]:
            continue
        if e[i]<minimum:
            minimum = e[i]
            pos = i
            
    return pos

def Preference(Wahl):
    if len(Wahl[0])==1:
        return Wahl[0][0]
    loser = LeastFirstPlaces(Wahl)
    # verlierer der Runde wird aus den Listen gestrichen:
    # neueWahl =
    for liste in Wahl:
        liste.remove(loser)
    return Preference(Wahl)

def Coombs(Wahl):
    if len(Wahl[0])==1:
        return Wahl[0][0] # alle Wähler haben gleichen Kandidaten
    loser = MostLastPlaces(Wahl)
    # verlierer der Runde wird aus den Listen gestrichen:
    for liste in Wahl:
        liste.remove(loser)
    return Coombs(Wahl)
        
s=set([1])

counter = 0
erg=[0,0,0,0]

while erg[0]==erg[2]:#len(s)<4:
    erg = [None]*4
    wahlrunde = neueWahl()
    

    copya = list(wahlrunde)#[:]
    copyb = list(wahlrunde)#wahlrunde[:]
    copyc = list(wahlrunde)#wahlrunde[:]
    copyd = list(wahlrunde)#wahlrunde[:]

    print "a",copya
    erg[0] = relativ(copya)
    
    print "b",copyb
    erg[1] = borda(copyb)
    
    
    print "d",copyd
    erg[3] = Coombs(copyd)
    
    print "c",copyc
    erg[2] = Preference(copyc)



    s = set(erg) # Umwandlung in Menge
    counter += 1
    #if counter % 2000 ==0:
    #    print erg
    #    print counter
    break
else:
    # print erg
    print "fertig: wahl=",wahlrunde
     
Erwarte das Beste und sei auf das Schlimmste vorbereitet.
Erwin
User
Beiträge: 141
Registriert: Donnerstag 9. Juni 2005, 08:51

Nikolas hat geschrieben: Wenn ich aber direkt:
L=range(3)
K=L[:]
K.delete(2)
ausführe, besteht L immer noch aus drei Elementen.
Sollte L nicht weiterhin aus 3 Elementen bestehen?
Immerhin hast doch Anfangs mittels range ja 3 Elemente entstehen lassen?
Und L mittels 'K=L[:]' doch deshalb kopiert, damit L unbeeinflusst bleibt, oder?

'K.delete(2)'?
Das klappt bei Dir?
Bei mir heißt es da, dass Listen diesen Befehl nicht haben.
Aber vielleicht habe ich ja auch was falsch gemacht.
Ich mache nie einen Fehler Zweimal.
Schließlich ist die Auswahl ja groß genug.
BlackJack

@Nikolas: Mit der Slice-Notation oder `list()` erzeugst Du eine *flache* Kopie. Bei Deinen verschachtelten Listen erzeugts Du eine neue Liste, die als Elemente Referenzen auf die gleichen Listen enthält wie die Originalliste.

Mach in den Funktionen, die Kandidaten in den Listen streichen tiefe Kopien mit `copy.deepcopy`. Letztendlich solltest Du übrigens dort die Kopien machen, wo sie auch gebraucht werden und nicht ausserhalb.

Ausserdem bin ich mir nicht so ganz sicher ob es richtig ist, das `MostLastPlaces` einen *Index* liefert, der dann als *Wert* aus einer Liste entfernt wird!?

Die Rekursionen würde ich in Schleifen umwandeln.

Edit: Was soll das erhöhen der ersten Plätze in `relativ()`? Und was soll die Funktion überhaupt machen? Ich hätte da eher erwartet, dass ein Histrogramm der ersten Plätze erstellt wird und der Kandidat, der am häufigsten auf Platz 1 war gewinnt!? Und wie geht das Programm damit um, wenn mehere Kandidaten gleich bewertet werden?
Nikolas
User
Beiträge: 102
Registriert: Dienstag 25. Dezember 2007, 22:53
Wohnort: Freiburg im Breisgau

aso. Das mit der flachen und tiefen Kopie wusste ich noch gar nicht. Find ich auch etwas unintuitiv :roll:

>Ausserdem bin ich mir nicht so ganz sicher ob es richtig ist, das `MostLastPlaces` einen *Index* liefert, der dann als *Wert* aus einer Liste entfernt wird!?

Doch, das ist schon so gedacht :) Ich habe die Kandidaten von 0 bis K-1 durchnummeriert. Wenn ich also eine bei einem Wähler an der ersten Stelle eine '1' lese, kann ich das auch als Index in einer Liste nutzen, um die erste Plätze zu zählen. Und zurück geht es natürlich dann genauso. Und da ich sicher einen Kandidaten habe, der eine erste Stelle gemacht hat, bin ich auch sicher, dass der Index, der mit max gefunden wurde, auch noch ein Element in meinen Wählerlisten ist. Wenn ich das Minimum suche, ist das nicht mehr gegeben, deswegen ist das LeastFirstPlaces auch etwas länger, da ich diesen Trick nicht anwenden darf.


zu deinem Edit:
>Ich hätte da eher erwartet, dass ein Histrogramm der ersten Plätze erstellt wird und der Kandidat, der am häufigsten auf Platz 1 war gewinnt!?
Genau das wird gemacht. Da KandidatenNummer = IndexNummer baue ich damit ein Histogramm. Wenn mehrere Leute die gleiche Anzahl haben, gewinnt der mit kleinerem Index, da index() nach dem ersten Auftreten einer Zahl in einer Liste sucht.
Erwarte das Beste und sei auf das Schlimmste vorbereitet.
Antworten