0

I'm trying to build a dictionary using keys that come from [the values of] a tuple, and the value of those keys should be a new dictionary formed from the keys of a dictionary and the value of the sub-key initialized to 0.

The tuple looks like:

characters = ('Fred', 'Sam', 'Bob', 'Daisy', 'Gina', 'Rupert')

The dictionary involved looks like:

jobs = {
    'Pizzeria': 1,
    'Mall Kiosk': 2
    'Restaurant': 3
    'Burger Joint': 4
    'Department Store': 5
}

I'd like the final structure to look like:

jobsWorkedCounter = {
    'Fred': {
        'Pizzeria': 0,
        'Mall Kiosk': 0
        'Restaurant': 0
        'Burger Joint': 0
        'Department Store': 0
    },
    'Sam': {
        'Pizzeria': 0,
        'Mall Kiosk': 0
        'Restaurant': 0
        'Burger Joint': 0
        'Department Store': 0
    },

    ...

    'Rupert': {
        'Pizzeria': 0,
        'Mall Kiosk': 0
        'Restaurant': 0
        'Burger Joint': 0
        'Department Store': 0
    },
}

The end goal is to have a structure for incrementing counters:

jobsWorkedCounter['Fred']['Burger Joint'] += 1

I've tried using various nested comprehensions:

jobsWorkedCounter = { char: dict((key, 0) for key in jobs.keys()) for char in characters }

# and

jobsWorkedCounter = { char: dict(jobs.keys(), 0) for char in characters }

# and

jobsWorkedCounterDict = { key: 0 for key in jobs.keys() }
jobsWorkedCounter = { char: jobsWorkedCounterDict for char in characters }

# and

jobsWorkedCounter = { char: { key: 0 for key in jobs.keys() } for char in characters }

and a simple for loop:

jobsWorkedCounter = { char: {} for char in characters }
    for char in characters:
        jobsWorkedCounter[char] = dict.fromkeys(jobs.keys(), 0)

but the best I've been able to accomplish is a single sub-key instead of the full set:

jobsWorkedCounter = {
    'Fred': {
        'Pizzeria': 0,
    },
    'Sam': {
        'Pizzeria': 0,
    },

    ...

    'Rupert': {
        'Pizzeria': 0,
    },
}

It seems that no matter what I try, I'm managing to flatten the new dictionary down to a single key-value pair and that's what gets assigned to the key from the tuple.

How can I accomplish what I'm trying to do?

Also, just in case I'm doing this incorrectly as well, to check the output I'm doing this:

keys = jobsWorkedCounter['Fred'].keys()
raise Exception(keys)

which gets me:

Exception: [u'Pizzeria']

where I would expect to see:

Exception: [u'Pizzeria', u'Mall Kiosk', u'Restaurant', u'Burger Joint', u'Department Store']  

I'm fairly sure this method of seeing the keys should work because if I change it to:

keys = jobsWorkedCounter.keys()
raise Exception(keys)

I get:

Exception: [u'Fred', u'Sam', u'Bob', u'Daisy', u'Gina', u'Rupert']

Addendum

I'm stuck using Python 2.7 as I'm in a Ren'Py environment (hence the reason for raising an exception to see the output).

For example:

from pprint import pprint

gives me:

Import Error: No module named pprint
pete
  • 24,141
  • 4
  • 37
  • 51
  • all your solutions would work in standard Python, perhaps you should write upfront that it is on Ren'Py? Also, all your trials involve comprehensions, maybe you need to avoid them? Check my answer for one way of doing so. – norok2 Jul 24 '19 at 18:41

2 Answers2

1

Using dict comprehensions:

characters = ('Fred', 'Sam', 'Bob', 'Daisy', 'Gina', 'Rupert')

jobs = {
    'Pizzeria': 1,
    'Mall Kiosk': 2,
    'Restaurant': 3,
    'Burger Joint': 4,
    'Department Store': 5
}

jobsWorkedCounter = {c: {k: 0 for k in jobs} for c in characters}

# For pretty print:
#from pprint import pprint
#pprint(jobsWorkedCounter)

print(jobsWorkedCounter)

Prints:

{'Bob': {'Burger Joint': 0,
         'Department Store': 0,
         'Mall Kiosk': 0,
         'Pizzeria': 0,
         'Restaurant': 0},
 'Daisy': {'Burger Joint': 0,
           'Department Store': 0,
           'Mall Kiosk': 0,
           'Pizzeria': 0,
           'Restaurant': 0},
 'Fred': {'Burger Joint': 0,
          'Department Store': 0,
          'Mall Kiosk': 0,
          'Pizzeria': 0,
          'Restaurant': 0},
 'Gina': {'Burger Joint': 0,
          'Department Store': 0,
          'Mall Kiosk': 0,
          'Pizzeria': 0,
          'Restaurant': 0},
 'Rupert': {'Burger Joint': 0,
            'Department Store': 0,
            'Mall Kiosk': 0,
            'Pizzeria': 0,
            'Restaurant': 0},
 'Sam': {'Burger Joint': 0,
         'Department Store': 0,
         'Mall Kiosk': 0,
         'Pizzeria': 0,
         'Restaurant': 0}}

EDIT: Another, explicit version:

zeroed_jobs = dict((k, 0) for k in jobs)
jobsWorkedCounter = {c: dict(**zeroed_jobs) for c in characters}

print(jobsWorkedCounter)
Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
  • Amended question to include the Ren'Py environment (where I cannot apparently import `pprint`). The output I'm getting from the dictionary comprehension is unchanged... a single sub-key is all I get. – pete Jul 24 '19 at 18:18
  • running `jobsWorkedCounter = {c: {k: 0 for k in jobs} for c in characters}` gets me `Exception: [u'Pizzeria']` – pete Jul 24 '19 at 18:21
  • @pete I updated my answer and added another (more explicit) version. Running this with Python2.7 gives my correct answer on my computer (like the first one) – Andrej Kesely Jul 24 '19 at 18:27
  • @AndrejKesely That is because it is using Ren'Py. I am not familiar with it, but from quickly going through it, it is not exactly Python... – norok2 Jul 24 '19 at 18:28
  • 1
    @norok2 I see, quickly googling around it seems it's some game with programming aspect in it? The interpreter seems to be limited though – Andrej Kesely Jul 24 '19 at 18:31
  • @norok2, @AndrejKesely Ren'Py is a game engine, built on python 2.7, which allows you to mix in actual Python code with game engine code, and normal pythonic things work as expected (regular list comprehensions for instance). Added `renpy` tag though, just in case. – pete Jul 24 '19 at 18:51
  • Also copy/pasted your explicit version in and got the same result: `Exception: [u'Pizzeria']` – pete Jul 24 '19 at 18:52
1

I created a new Ren'Py project (from Ubuntu 18.04) and added the following code at the beginning of screens.rpy. This is basically one of your tentatives:

init python:
    characters = ('Fred', 'Sam', 'Bob', 'Daisy', 'Gina', 'Rupert')

    jobs = {
        'Pizzeria': 1,
        'Mall Kiosk': 2,
        'Restaurant': 3,
        'Burger Joint': 4,
        'Department Store': 5
    }

    jobsWorkedCounter = {char: {key: 0 for key in jobs.keys()} for char in characters}
    keys = jobsWorkedCounter['Fred'].keys()
    raise Exception(keys)

And I get:

I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/screens.rpy", line 5, in script
    init python:
  File "game/screens.rpy", line 19, in <module>
    raise Exception(keys)
Exception: [u'Department Store', u'Pizzeria', u'Restaurant', u'Mall Kiosk', u'Burger Joint']

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "game/screens.rpy", line 5, in script
    init python:
  File "/usr/share/games/renpy/renpy/ast.py", line 848, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "/usr/share/games/renpy/renpy/python.py", line 1812, in py_exec_bytecode
    exec bytecode in globals, locals
  File "game/screens.rpy", line 19, in <module>
    raise Exception(keys)
Exception: [u'Department Store', u'Pizzeria', u'Restaurant', u'Mall Kiosk', u'Burger Joint']

Linux-4.15.0-55-generic-x86_64-with-Ubuntu-18.04-bionic
Ren'Py 6.99.14.1.3218
test_renpy 1.0
Wed Jul 24 21:03:28 2019

so, I would tend to think you have a bug somewhere else in your code.

norok2
  • 25,683
  • 4
  • 73
  • 99
  • Tried it (copy/pasted) and the end result is the same as I've been getting (`Exception: [u'Pizzeria']`) – pete Jul 24 '19 at 18:49
  • 1
    @pete I actually tested this in Ren'Py and for me it works as you would expect. There must be some other issue with your scripts. – norok2 Jul 24 '19 at 19:06
  • 2
    Okay, I figured out the problem... I was loading a saved game (to save time, rather than go through the story intro all over again) and the saved game had the old values for `jobsWorkedCounter` in it, which is why I was continuously getting the same output again and again. Started a fresh game and both your solution and @AndrejKesely's did indeed work as expected. Accepting your answer (but upvoting @AndrejKesely's) as you pointed out it was a bug elsewhere which got me thinking about it in a different frame of mind. Thank you both for your help. – pete Jul 24 '19 at 19:21