0

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"
    }
  ]
}
BananaMaster
  • 377
  • 6
  • 15
  • It's hard to understand what you mean without providing some real data you're working with. Can you update the question with that? Either way, my advice would be not to try and do all the transformation in one step. Create a function or two where you pull out and clear the data and use that in your list comprehension. – Milan Cermak May 26 '20 at 14:43
  • I edited the post hopefully adding enough data but not making it overwhelming. Please let me know if its okay. As for the breaking it down idea, it's a lot of data and doing it in as less steps as possible saves a lot of time and resources. – BananaMaster May 26 '20 at 15:10

1 Answers1

1

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.

jferard
  • 7,835
  • 2
  • 22
  • 35