4

I have list of dictionaries and list of integers

x = [
    {
        "name": "tom",
        "job": "judge"
    },
    {
        "name":"bob",
        "job": "policeman"
    }
]
y = [1000, 2200]

I want to zip them and add y elements to dictionaries as "payroll": y_element The desired output would be:

[
    {
        "name": "tom",
        "job": "judge",
        "payroll": 1000
    },
    {
        "name":"bob",
        "job": "policeman",
        "payroll": 2200
    }
]

I actually achieved that by:

z = zip(x, y)
for i in z:
    i[0]["payroll"] = i[1]

z = [i[0] for i in z]

But I was wondering whether it could be done in dict comprehension in list comprehension. This is what I tried so far:

z = [{k: v, "value": o} for d, o in z for k, v in d.items()]

Obviously it is wrong because the output is:

{'name': 'bob', 'job': 'policeman', 'value': 2}
DeepSpace
  • 78,697
  • 11
  • 109
  • 154
M.wol
  • 901
  • 3
  • 10
  • 21
  • I'm confused with your solution. Why not just `for d, num in zip(x, y): d['payroll'] = num` ? Why do you need all the indexing and the double loop? – DeepSpace Jun 03 '22 at 12:50

3 Answers3

9

You can merge the dict with the required data using ** here.

[{**d, 'payroll':i} for d, i in zip(x, y)]

# [{'name': 'tom', 'job': 'judge', 'payroll': 1000},
#  {'name': 'bob', 'job': 'policeman', 'payroll': 2200}]
Ch3steR
  • 20,090
  • 4
  • 28
  • 58
  • Actually this is a Python <3.9 valid answer, I don't think it would work in Python <3.5, but 3.4 is a deprecated version so this is a universally correct answer. +1 – FLAK-ZOSO Jun 03 '22 at 12:55
  • @FLAK-ZOSO Thanks for pointing it out. I haven't tested it on 3.4 but I'll take your word for it. – Ch3steR Jun 03 '22 at 12:58
  • 2
    @FLAK-ZOSO: Yep, 3.5 introduced [the additional unpacking generalizations from PEP 448](https://peps.python.org/pep-0448/), so that's the first version this would work on. – ShadowRanger Jun 03 '22 at 13:11
4

With python ≥3.9 you can use dictionary merging with the | operator:

out = [d | {'payroll': p} for d, p in zip(x, y)]

output:

[{'name': 'tom', 'job': 'judge', 'payroll': 1000},
 {'name': 'bob', 'job': 'policeman', 'payroll': 2200}]

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
mozway
  • 194,879
  • 13
  • 39
  • 75
  • When I think of Python 3.9 the first thing that always comes to my mind is that magic dict merging operator... nice answer, +1 – FLAK-ZOSO Jun 03 '22 at 12:48
  • 1
    @FLAK-ZOSO yes, I love it, I often realize this when I use a machine with older python version ;) – mozway Jun 03 '22 at 12:50
  • 2
    And `x = [{**d, **{'payroll': p}} for d, p in zip(x, y)]` on < 3.9 – DeepSpace Jun 03 '22 at 12:53
  • 1
    @DeepSpace: No need to make the temp `dict` just to unpack it though, you can mix individual keys and `dict`s to unpack; `{**d, 'payroll': p}` is the simpler (and faster) way to do it. Avoiding the temporary `dict` makes it an improvement on using `|`, where the temporary `dict` is required. – ShadowRanger Jun 03 '22 at 13:12
3

Speaking as someone who has done 100's (if not more..) of reviews over many years of other peoples code. I think the question should be whether you should try to do this in any form of comprehension. Readability of code is key, if nobody understand what you're trying to do, it is simply not maintainable. You'll forgot what it was supposed to do, comments will go out of sync (if any are there to begin with) with the code.

The most readable version in my opinion is the one that keeps it simple. Do note this does modifying the x in place. S

for index, dikt in enumerate(x):
    dikt["payroll"] = y[index] # fetch the payroll from the other list using the index

What would the gain be with one liner over this? One line and less readability. Yes, and showing you know 'comprehension', good for you! Nobody will give you a price over it. And me as a reviewer will add a issue saying "Don't do this. It decrease readability".

So pretty please; don't.

Disclaimer: Yes, there are always cases where a simple comprehension is also just good enough. But I've seen construction where people start looping over the result of a comprehensions and then further filter out the result.

Simple is better than complex. Complex is better than complicated.

The Pjot
  • 1,801
  • 1
  • 12
  • 20
  • 1
    One obvious difference is that the above loop modifies the dictionary in place, while a list comprehension generates a new object. Also, there are certainly cases where having a short code is extremely useful (i.e. in a function call), you would otherwise likely need a wrapper, adding an extra level of comprehension (pun not intended :p) – mozway Jun 03 '22 at 13:01
  • Yes, good point on the modifying in place. I'll place a disclaimer about that :) And yes, comprehension certainly has it's uses. But I've seen it abused a bit too often to be really rooting for it's usage :P – The Pjot Jun 03 '22 at 13:04
  • I completely agree, really good answer thanks! I will accept as solution the other one, as I was interested how to do it in comprehension – M.wol Jun 03 '22 at 13:06