BananaMaster
BananaMaster

Reputation: 557

Python: How can I add extra item in dictionary created via a loop?

I'm creating a table like this:

data = json.load(f)
num_of_certificates = (len(data.get('certificates')))
new_data = sorted([{n: f"{data.get('certificates', [{}])[i].get(n, 0)}"
                        for n in some_dic}
                      for i in range(num_of_items)], key=lambda x: (int(x['exp_date_year']), int(x['exp_date_month']), int(x['exp_date_day'])))

and I want to add an extra item. Imagine having one more "n" to loop through but I can't just add it in the "some_dic" for my reasons that dont affect this. I tried

data = json.load(f)
num_of_certificates = (len(data.get('certificates')))
new_data = sorted([{n: f"{data.get('certificates', [{}])[i].get(n, 0)}",
                    'test': 'test value'
                        for n in some_dic}
                      for i in range(num_of_items)], key=lambda x: (int(x['exp_date_year']), int(x['exp_date_month']), int(x['exp_date_day'])))

but it doesn't work. I made it work doing it like this:

data = json.load(f)
num_of_certificates = (len(data.get('certificates')))
new_data = sorted([{n: f"{data.get('certificates', [{}])[i].get(n, 0)}" if n is not "remaining_days" else "new_value"
                        for n in some_dic}
                      for i in range(num_of_certificates)], key=lambda x: (int(x['exp_date_year']), int(x['exp_date_month']), int(x['exp_date_day'])))

basically adding another empty thing inside "some_dic" but this creates other issues and I feel like there's a way easier way to do this. Here's the "some_dic" dictionary

    some_dic = {
    "name": False,
    "type": False,
    "exp_date_day": False,
    "exp_date_month": False,
    "exp_date_year": False,
    "color": False,
    "remaining_days": True
     }

Here's the json file im parsing:

{
  "certificates": [
    {
      "exp_date_year": "2020",
      "name": "1",
      "type": "1",
      "exp_date_day": "1",
      "exp_date_month": "1",
      "color": "1",
      "exp_date_day_of_year": 1
    },
    {
      "exp_date_year": "2020",
      "name": "2",
      "type": "2",
      "exp_date_day": "2",
      "exp_date_month": "2",
      "color": "2",
      "exp_date_day_of_year": 33
    },
    {
      "exp_date_year": "2022",
      "name": "3",
      "type": "3",
      "exp_date_day": "3",
      "exp_date_month": "3",
      "color": "3",
      "exp_date_day_of_year": "62"
    }
  ]
}

Upvotes: 0

Views: 59

Answers (1)

jferard
jferard

Reputation: 8180

First, you should probably une regular loops to avoid an overcomplicated expression like this.

Second, your f-string make no sense:

f"{data.get('certificates', [{}])[i].get(n, 0)}"

is the same as:

str(data.get('certificates', [{}])[i].get(n, 0))

Third, you can replace:

[{n: str(data.get('certificates', [{}])[i].get(n, 0)})
    for n in some_dic}
    for i in range(num_of_items)]

By:

[{n: str(c.get(n, 0)})
    for n in some_dic}
    for c in data.get('certificates', [{}])]

Because c will iterate over the elements of data['certificates'].

Fourth, since you are using only the keys of some_dic, you can write:

some_keys = {"name", "type", "exp_date_day", "exp_date_month", "exp_date_year", "color"}
L = [{n: str(c.get(n, 0)})
    for n in some_keys}
    for c in data.get('certificates', [{}])]
new_data = sorted(L, ...)

Fifth, I would test if certificates is in data before the list comprehension. Note that you return an empty list if data['certificates'] is an empty list or if the key certificates is not in data. I would rather raise an error in the second case:

if 'certificates' not in data:
    raise ValueError("Data is corrupted")
certificates = data['certificates']
L = [{k: str(c.get(n, 0)}) for k in some_keys} for c in certificates]
...

And sixth, the actual answer to your question, you want to add an element to the dict in one expression. See this question and the answers:

L = [{**{k: str(c.get(n, 0)}) for k in some_keys}, 'remaining_days': 'new_value'} for c in certificates]

Again, prefer regular loops unless this part of your code is a bottleneck.

Upvotes: 1

Related Questions