1

Given a list of runs up to a maximum reached stage, I would like to transfer the maximum values to a nested dictionary holding the number of tries (t) for each stage.

This means runs of 3, 4 and 7 should yield:

{0: {'t': 3}, 1: {'t': 3}, 2: {'t': 3}, 3: {'t': 2}, 4: {'t': 1}, 5: {'t': 1}, 6: {'t': 1}}

Stages 0,1,2 has been played for 3 times each, stage 3 for 2 times and stages 4, 5 and 6 only once.

  • I Get instead the following result:

    {0: {'t': 14}, 1: {'t': 14}, 2: {'t': 14}, 3: {'t': 14}, 4: {'t': 14}, 5: {'t': 14}, 6: {'t': 14}}
    

Source Code

p = {}
p = dict.fromkeys(range(7), {})

runs = (3, 4, 7)

for r in runs:
    for l in range(r):
        if "t" in p[l]:
          p[l]["t"] += 1
        else:
          p[l]["t"] = 1

Why are the values the same in all the dictionary's key?

Federico Baù
  • 6,013
  • 5
  • 30
  • 38
Frank
  • 11
  • 2
  • 1
    The documentation for [dict.fromkeys](https://docs.python.org/3/library/stdtypes.html#dict.fromkeys) says they share the same value. So the empty dict you pass in, `{}`, is shared between them all. – Peter Wood Dec 21 '20 at 11:28
  • 1
    See this answer: https://stackoverflow.com/a/43772300/1084416 – Peter Wood Dec 21 '20 at 11:31

2 Answers2

1

That is because dict.fromkeys() sets the same object for each key in p

Try doing something like this instead

p = { i : {} for i in range(7) }

runs = (3, 4, 7)

for r in runs:
    for l in range(r):
        if "t" in p[l]:
          p[l]["t"] += 1
        else:
          p[l]["t"] = 1
C.Georgiadis
  • 201
  • 3
  • 9
0
  • Use a Dict Comprehension

     p = {n:{} for n in range(7)}
      runs = (3, 4, 7)
    
      for r in runs:
          for l in range(r):
              if "t" in p[l]:
                  p[l]["t"] += 1
              else:
                  p[l]["t"] = 1
      print(p)
    

fromkeys() is a class method that returns a new dictionary. value defaults to None.

All of the values refer to just a single instance, so it generally doesn’t make sense for value to be a mutable object such as an empty list.

To get distinct values, use a dict comprehension instead.


Edit

Worth to mention:

  • Use setdefault Method:

     for r in runs:
              for l in range(r):
                  if "t" in p[l]:
                      p[l]['t'] += 1
                  else:
                      p[l].setdefault('t', 1)
    
  • Pre-Build the Dict with the Key 't' in it.

      p = {n: {'t': 0} for n in range(7)}
      runs = (3, 4, 7)
    
      for l in range(len(runs)):
          for run in range(runs[l]):
              p[run]['t'] += 1
    
Federico Baù
  • 6,013
  • 5
  • 30
  • 38