Python Dictionary meerdere values per key updaten

Pagina: 1
Acties:

  • HowsMyApple
  • Registratie: November 2010
  • Laatst online: 19:58
Ik vroeg mij af hoe (en of?) het mogelijk is om in python meerdere values aan een key in een dictionary mee te geven en te updaten?
De opzet zou er als volgt uit moeten zien: De keys zijn namen, deze hebben de values x, tijd en punten.

spelers = {}
punten = 0
tijd = 0
x = 0
spelers[names] = pt,tijd,x

Op deze manier krijg ik dus wel een dict entry zoals 'Henk': (0,0,0)
Het punt waar ik dus op vast loop is het individueel kunnen updaten van values. Ik haal ergens anders mijn berekening voor het aantal punten vandaan, hoe zorg ik er dan voor dat ik voor key "Henk" de value "punten" kan updaten?

(Hoop dat het enigszins duidelijk is, zo niet zeg dan gerust wat er duidelijker moet)

Acties:
  • +2 Henk 'm!

  • Morrar
  • Registratie: Juni 2002
  • Laatst online: 09-10 13:33
Gewoon een list of dict opnemen in de spelers dict? Die kun je dan weer updaten.

Python:
1
2
3
4
5
6
7
8
9
10
11
# Spelers dictionairy aanmaken
spelers = {}

# Henkie als speler toevoegen
spelers['Henkie'] = {'leeftijd': 30, 'score': 4}

# Alleen leeftijd van Henkie aanpassen
spelers['Henkie']['leeftijd'] = 31

# Hele record van Henkie vervangen
spelers['Henkie'] = {'leeftijd': 31, 'score': 5}


Als je het netter wilt doen, kun je een Speler class aanmaken met nette getter en setter methodes... Dat ziet er dan ongeveer zo uit:

Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class Speler:
    def __init__(self, leeftijd, punten=0):
        # Variabelen initialiseren
        self._leeftijd = leeftijd
        self._punten = punten
    
    @property
    def leeftijd(self):
        # Retourneer de leeftijd
        return self._leeftijd
    
    @leeftijd.setter
    def leeftijd(self, leeftijd):
        # Check bereik van leftijd
        if 0 < leeftijd < 120:
            self._leeftijd = leeftijd
        else:
            raise ValueError('Leeftijd valt buiten geldig bereik (0-120)!')
   
    @property
    def punten(self):
        # Retourneer aantal punten
        return self._punten
    
    @punten.setter
    def punten(self, aantal):
        # Aantal punten moet positief zijn
        if aantal >= 0:
            self._punten = aantal
        else:
            raise ValueError('Punten moet een positief getal zijn!')
   
    def set(self, **kwargs):
        # Check op leeftijd in argumenten
        if 'leeftijd' in kwargs:
            self.leeftijd = kwargs['leeftijd']
        
        # Check op punten in argumenten
        if 'punten' in kwargs:
            self.punten = kwargs['punten']
    
    def __str__(self):
        # Converteer speler naar string voor printen
        return 'Leeftijd: %d --- Punten: %d' % (self.leeftijd, self.punten)
        
        
### Test code
spelers = {}
spelers['Henkie'] = Speler(30, 4)
print(spelers['Henkie'])

# Update leeftijd en punten
spelers['Henkie'].leeftijd = 31
spelers['Henkie'].punten = 5
print(spelers['Henkie'])

# Dit geeft een foutmelding voor buiten bereik
# spelers['Henkie'].leeftijd = 130

# Update leeftijd en punten tegelijk
spelers['Henkie'].set(leeftijd=32, punten=6)
print(spelers['Henkie'])


Noot: Python 3.5 syntax btw.

Zoals je ziet kun je in de setter methodes nog wat extra checks inbouwen; daarom is deze manier netter dan direct variabelen aanpassen in het object. Je zou dit eventueel ook in de getter methodes kunnen toepassen, bijvoorbeeld voor het formatteren van getallen of datums.

De set() methode maakt gebruik van een speciale constructie met **kwargs. De variabele kwargs bevat alle argumenten waarme de methode is aangeroepen als een {key: value} dictionary. Deze kun je vervolgens opvragen en gebruiken. Merk op dat de set() methode ook gebruikt maakt van de setter methodes, waardoor de checks ook uitgevoerd worden.

De __str__() methode is er alleen om het object netjes te kunnen printen.

[ Voor 162% gewijzigd door Morrar op 15-12-2016 15:26 ]


  • HowsMyApple
  • Registratie: November 2010
  • Laatst online: 19:58
Top, hier kan ik zeker wat mee! Werken met dictionaries is sowieso nieuw voor mij, wist dan ook niet dat je met lists binnen je dictionary kon werken.
Ik ga er eens mee aan de slag, thanks!

Acties:
  • 0 Henk 'm!

  • HowsMyApple
  • Registratie: November 2010
  • Laatst online: 19:58
Het is inmiddels gelukt met behulp van je uitleg! Probleem waar ik nu tegenaanloop is dat ik niet op 1 bepaalde value (van de 6) kan sorteren. Op internet zijn er meer dan genoeg voorbeelden te vinden voor het sorteren op op value als er slechts 1 value is, maar geen duidelijke voor wanneer er meerdere values zijn.

Acties:
  • 0 Henk 'm!

  • Daos
  • Registratie: Oktober 2004
  • Niet online
Al eens hier gekeken?

En kan je een (versimpeld) voorbeeld geven? Ik kan uit je tekst niet echt opmaken wat je wilt.

Acties:
  • 0 Henk 'm!

  • Morrar
  • Registratie: Juni 2002
  • Laatst online: 09-10 13:33
Je kan een lambda functie gebruiken voor sorteren:

sorted(spelers, key=lambda s: s['leeftijd'])

Sorteert spelers op leeftijd key. De lambda functie is een inline functie met s als argument. De functie retourneert de leeftijd key van het argument s (deze key moet wel bestaan voor alle spelers!).

Sorted roept de lambda functie aan en geeft de spelers 1 voor 1 door. Aangezien het de leeftijden terugkrijgt sorteert het daarop in oplopende volgorde. Als je aflopend wilt hebben, retourneer dan -s['leeftijd'] in de lambda functie.

[ Voor 60% gewijzigd door Morrar op 17-12-2016 17:13 ]


Acties:
  • 0 Henk 'm!

  • HowsMyApple
  • Registratie: November 2010
  • Laatst online: 19:58
Daos schreef op zaterdag 17 december 2016 @ 16:59:
Al eens hier gekeken?

En kan je een (versimpeld) voorbeeld geven? Ik kan uit je tekst niet echt opmaken wat je wilt.
Tot nu toe krijg ik het enkel voor elkaar om te sorteren op de key, en niet op een value.

Op het moment heb ik de dictionary op deze manier opgebouwd:
code:
1
2
spelers = {}
spelers[names] = {'pt': 0, 'wp': 0, 'sb' : 0, 'z' : 0, 'opp' : "",'win' : "", 'draw' : ""}


Wat ik graag wil is dat ik in eerste instantie sorteer op de value "pt". (En indien meerdere key's een zelfde 'pt' value hebben daarna sorteren op 'wp').
Morrar schreef op zaterdag 17 december 2016 @ 17:05:
Je kan een lambda functie gebruiken voor sorteren:

sorted(spelers, key=lambda s: s['leeftijd'])

Sorteert spelers op leeftijd key. De lambda functie is een inline functie met s als argument. De functie retourneert de leeftijd key van het argument s (deze key moet wel bestaan voor alle spelers!).

Sorted roept de lambda functie aan en geeft de spelers 1 voor 1 door. Aangezien het de leeftijden terugkrijgt sorteert het daarop in oplopende volgorde. Als je aflopend wilt hebben, retourneer dan -s['leeftijd'] in de lambda functie.
sorted(spelers, key=lambda s: s['leeftijd'])

Heb inderdaad ook al met ˆsoortgelijke code zitten tobben, maar krijg dan de TypeError 'string indices must be integers, not str'. Dus blijkbaar doe ik nog iets anders fout.

Bouw ik de dictionary uberhaupt wel goed op door 'm aan te maken als spelers = {} en vervolgen dus per speler die toe te voegen dmv:
code:
1
spelers[names] = {'pt': 0, 'wp': 0, 'sb' : 0, 'z' : 0, 'opp' : "",'win' : "", 'draw' : ""}

[ Voor 45% gewijzigd door HowsMyApple op 17-12-2016 19:06 ]


Acties:
  • 0 Henk 'm!

  • Daos
  • Registratie: Oktober 2004
  • Niet online
Site uit mijn vorige post ligt plat -O-

Misschien moet je inderdaad je data anders opslaan. Bijvoorbeeld zo:

Python:
1
2
3
4
5
6
7
8
9
10
spelers = [
    {'naam': 'Henkie', 'leeftijd': 30, 'score': 4},
    {'naam': 'Klaas', 'leeftijd': 25, 'score': 3},
    {'naam': 'Jan', 'leeftijd': 24, 'score': 7},
    {'naam': 'Piet', 'leeftijd': 33, 'score': 7}
]

s = sorted(spelers, key=lambda s: s['leeftijd'])

print(s)


Hoe je dan op meerdere dingen kan sorteren kan je vinden met google. We mogen hier op dit forum niet te veel voorzeggen O-)

Acties:
  • 0 Henk 'm!

  • Morrar
  • Registratie: Juni 2002
  • Laatst online: 09-10 13:33
Mja slordig van mij: ik zit in het buitenland en heb even geen Python bij de hand...

Probleem is inderdaad dat je een dict probeert te sorteren, terwijl deze inherent geen volgorde hebben. Je kunt wel een lijst van gesorteerde tuples krijgen:

sorted(spelers.items(), key=lambda t: t[1]['leeftijd'])

Of voor meerdere keys:

sorted(spelers.items(), key=lambda t: (t[1]['leeftijd'], t[1]['score']))

Wellicht is een OrderedDict ook wel een uitkomst in dit geval (zie collections).

De structuur die Daos voorstelt is eigenlijk netter, alleen heb je dan niet de mogelijkheid om spelers snel op naam te vinden. Daar zul je dan zelf iets voor moeten implementeren.

Wellicht ook iets om over na te denken: naam hoeft niet altijd uniek te zijn...

[ Voor 30% gewijzigd door Morrar op 17-12-2016 23:19 ]

Pagina: 1