sai krishna
sai krishna

Reputation: 21

Python dictionary comprehension to contain list of items not found in another dictionary

There is a list and a dictionary. If an item in the list is not present in the dictionary add the item to a new dictionary. Below is the for loop which I'm trying to convert to dictionary comprehension.

for i in range(1, len(list_a)):
    if dict_main.get(list_a,'') == '':
        dict_new[list_a[i]] = None

Dictionary comprehension method as follows

dict_new = {list_a[i] if dict_main.get(list_a[i], '') == '' else None: None for i in range(1, len(list_a))}

Comprehension works fine but it adds an extra (None, None) key value pair. If else is removed it throws 'else expected' error. Please guide me.

Upvotes: 0

Views: 1406

Answers (1)

jferard
jferard

Reputation: 8180

You have several issues in the code of your regular loop:

  • list indices start at 0, hence you should write for i in range(0, len(list_a)) or you will miss the first element of the list.
  • a probable typo: dict_main.get(list_a,'') should be dict_main.get(list_a[i],'').
  • what happens if you have a mapping x: '' in the dict? dict_main.get(x, '') returns '' and the mapping x: None is added to dict_new. Use x not in d to check if the key x is not mapped to a value in d.
  • not really an issue, but in Python you can write for x in my_list to iterate over the elements of a list if you don't need the index (if you need the index, enumerate is useful).

The rule of thumb is: first, fix the regular loop and then create a list/dict comprehension. Here's the fixed regular loop:

for x list_a:
    if x not in dict_main:
        dict_new[x] = None

Hence the dict comprehension (given in comment by @Kenny Ostrom):

dict_new = {x: None for x in list_a if x not in dict_main}

If you really need to produce a dict whose values are None, you can use dict.fromkeys with a collection of keys:

dict_new = dict.fromkeys(x for x in list_a if x not in dict_main)

Or, maybe clearer:

dict_new = dict.fromkeys(set(list_a) - set(dict_main))

Your dict comprehension trial is not filtered (no if at the end). It creates len(list_a) keys in the target dictionary, all mapped to None. Those keys are the elements of the list if dict_main.get(list_a[i], '') == '' (element not in dict_main or mapped to ''), else None.

If several elements of the list are keys of the dict_main, the mapping None: None is added once then overriden because the keys of a dictionary are unique. This is why you have one (and only one) extra None: None at the end of the dictionary as soon as you have at least one element in the list that is a key of dict_main.

Upvotes: 1

Related Questions