Need help to remove empty lists from dictionaries - python

I have this dictionary:
a_dict = {1: "hello", 2: [], 3: [], 4: "hey", 5:"phone"}
And I want to remove all the empty lists from this dictionary.
Output: a_dict = {1:"hello",4:"hey",5:"phone"}
I tried this:
for item in a_dict:
if a_dict[item] == []:
del item
However, this just gives back the original dictionary. It doesn't do anything to it.

You should not be deleting key of a dict while you are iterating it. You can save your keys in some other variable and use it to delete keys. Here is a solution very much similar to your current code.
deleteKeys = []
for item in a_dict:
if a_dict[item] == []:
deleteKeys.append(item)
for i in deleteKeys:
del a_dict[i]

Related

How to remove dict where certain key is None

I want to delete a dictionary where certain key is None.
For example I have a list of dictionaries like:
my = [{"mydata": ""}, {"mydata": "hello"}]
What I did is:
for my_list in my:
if my_list["mydata"] == "":
my_list.clear()
But this gives:
[{}, {'mydata': 'hello'}]
I want that {} empty dictionary to be removed, How can I achieve it ?
My desired result format is :
{"my_data": "hello"}
Try this:
my = [{"mydata":""},{"mydata":"hello"}]
my2=[x for x in my if x['mydata']!='']
print(my2)
try list comprehension with any or all depending on your usecase.
In the example given by you if there is only one key in the dict then all and any won't make much difference.
my = [{"mydata":""},{"mydata":"hello"}]
my_new = [i for i in my if any(i.values())] #[{'mydata': 'hello'}]
Use List Comprehension
my = [{"mydata": ""}, {"mydata": "hello"}, {"mydata": "bye"}, {"mydata": ""}]
new_my = [{x: y} for i in my for x,y in i.items() if y != ""]
print(new_my)
[{'mydata': 'hello'}, {'mydata': 'bye'}]
Use remove() rather than clear(), and iterate over a copy of the list to avoid issues
for my_list in my[:]:
if my_list["mydata"] == "":
my.remove(my_list)

iteratively appending N items to list gives last item N times instead

I am accessing a list of dictionary items list_of_dict = [{'ka':'1a', 'kb':'1b', 'kc':'1c'},{'ka':'2a'},{'ka':'3a', 'kb':'3b', 'kc':'3c'}], and trying to conditionally append each entry to another list article_list using a function add_entries.
My desired output
article_list = [{x:1a, y:1b, z:1c}, {x:2a}, {x:3a, y:3b, z:3c}]
My code:
def add_entries(list_of_dict):
keys = ['x','y','z']
#defining a temporary dictionary here
my_dict = dict.fromkeys(keys,0)
entry_keys = ['ka','kb','kc']
my_list = []
for item in list_of_dict:
# conditionally append the entries into the temporary dictionary maintaining desired key names
my_dict.update({a: item[b] for a,b in zip(keys, entry_keys) if b in item})
my_list.append(my_dict)
return my_list
if __name__ == "__main__":
list_of_dict = [{'ka':'1a', 'kb':'1b', 'kc':'1c'},{'ka':'2a'},{'ka':'3a', 'kb':'3b', 'kc':'3c'}]
article_list = []
returned_list = add_entries(list_of_dict)
article_list.extend(returned_list)
My output
article_list = [{x:3a, y:3b, z:3c}, {x:3a, y:3b, z:3c}, {x:3a, y:3b, z:3c}]
Whats wrong
my_list.append(my_dict) appends a reference to the my_dict object to my_list. Therefore, at the end of the for loop in your example, my_list is a list of references to the exact same dictionary in memory.
You can see this for yourself using the function id. id, at least in CPython, basically gives you the memory address of an object. If you do
article_list.extend(returned_list)
print([id(d) for d in article_list])
You'll get a list of identical memory addresses. On my machine I get
[139920570625792, 139920570625792, 139920570625792]
The consequence is that updating the dictionary affects 'all of the dictionaries' in your list. (quotes because really there are not multiple dictionaries in your list, just many times the exact same one). So in the end, only the last update operation is visible to you.
A good discussion on references and objects in Python can be found in this answer https://stackoverflow.com/a/30340596/8791491
The fix
Moving the definition of my_dict inside the for loop, means that you get a new, separate dictionary for each element of my_list. Now, the update operation won't affect the other dictionaries in the list, and my_list is a list of references to several different dictionaries.
def add_entries(list_of_dict):
keys = ['x','y','z']
entry_keys = ['ka','kb','kc']
my_list = []
for item in list_of_dict:
#defining a new dictionary here
my_dict = dict.fromkeys(keys,0)
# conditionally append the entries into the temporary dictionary maintaining desired key names
my_dict.update({a: item[b] for a,b in zip(keys, entry_keys) if b in item})
my_list.append(my_dict)
return my_list
You can use this.
keys=['x','y','z']
res=[{k1:d[k]} for d in list_of_dict for k,k1 in zip(d,keys)]
output
[{'x': '1a'},
{'y': '1b'},
{'z': '1c'},
{'x': '2a'},
{'x': '3a'},
{'y': '3b'},
{'z': '3c'}]
Try this:
list_new_d=[]
for d in list_of_dict:
new_d={}
for k,v in d.items():
if k == 'ka':
new_d['x'] = v
if k == 'kb':
new_d['y'] = v
if k == 'kc':
new_d['z'] = v
list_new_d.append(new_d)

Find value in list of dicts and return id of dict

I'd like to try and find if a value is in a list of dicts, which can be done easily with:
if any(x['aKey'] == 'aValue' for x in my_list_of_dicts):
But this is only a boolean response, I'd like to not only check if the value is there, but to also access it afterwards, so something like:
for i, dictionary in enumerate(my_list_of_dicts):
if dictionary['aKey'] == 'aValue':
# Then do some stuff to that dictionary here
# my_list_of_dicts[i]['aNewKey'] = 'aNewValue'
Is there a better/more pythonic way of writing this out?
With next function, if expected to find only one target dict:
my_list_of_dicts = [{'aKey': 1}, {'aKey': 'aValue'}]
target_dict = next((d for d in my_list_of_dicts if d['aKey'] == 'aValue'), None)
if target_dict: target_dict['aKey'] = 'new_value'
print(my_list_of_dicts)
The output (input list with updated dictionary):
[{'aKey': 1}, {'aKey': 'new_value'}]
You can use a list comprehension. This will return a list of dictionaries that match your condition.
[x for x in my_list_of_dicts if x['aKey']=='aValue' ]

Convert multi-line slash-delimited string into a nested dictionary

abc/pqr123/xy2/yes//T
abc/pqr245/kl3/yes//T
abc/ijk123/op5/yes//T
abc/pqr245/kl4/yes//T
These are the input values that I want to convert to a nested dictionary.Each value such as
abc, pqr123, xy2, yes, T
represents the name of a product.
My output should look something like this:
{"abc":{"pqr123":{"xy2":{"yes":{"T":[]}},"pqr245":"kl3":{"yes":{"T":
[]}},"kl4":{"yes":{"T":[]}},"ijk123":{"op5":{"yes":{"T":[]}}}
So I need a nested dictionary of all unique values and at the last key of the dictionary should have a value of empty list.
Below is my snippet of code that generates the output I require, but I want to do it more dynamically so it is best suited even
if the length of the input grows or shrinks. Please do let me know if are any better solution for this problem.
data_dict={}
for item in meta_line.split(','):
item = item.replace('//','/')
item = str(item)
item = item.split('/')
if item[0] == "":
continue
if item[0] not in data_dict.keys():
data_dict[item[0]] = {}
if item[1] not in data_dict[item[0]].keys():
data_dict[item[0]][item[1]] = {}
if item[2] not in data_dict[item[0]][item[1]].keys():
data_dict[item[0]][item[1]][item[2]] = {}
if item[3] not in data_dict[item[0]][item[1]][item[2]].keys():
data_dict[item[0]][item[1]][item[2]][item[3]] = {}
if item[4] not in data_dict[item[0]][item[1]][item[2]][item[3]].keys():
data_dict[item[0]][item[1]][item[2]][item[3]][item[4]] = []
You probably want something that's not dependent on so many massively nested brackets. This is a problem that using references to a mutable object will work well on.
meta_line = 'abc/pqr123/xy2/yes//T,abc/pqr245/kl3/yes//T,abc/ijk123/op5/yes//T,abc/pqr245/kl4/yes//T'
data = dict()
for item in meta_line.split(','):
dref = data
dict_tree = item.strip().replace('//', '/').split('/')
for i, val in enumerate(dict_tree):
if val in dref:
pass
elif i != len(dict_tree) - 1:
dref[val] = dict()
elif i == len(dict_tree) - 1:
dref[val] = list()
dref = dref[val]
Every iteration of the inner loop will move the reference dref down a level, and then reset it on every iteration of the outer loop. At the end, data should hold your nested dict.
Edit: Sorry, I just noticed that you wanted the last level to be a list. This is one solution to that problem, but isn't the best (it will create errors if there's a list in a spot that a later data entry wants to be a dict instead). I would probably choose to build my nested dict and then recursively replace any empty dicts with empty lists afterwards to avoid that problem.
You can use The dict.setdefault method in a loop to build the nested dictionary. I'll use the pprint module to display the output. Note that pprint.pprint sorts dictionary keys before the output is computed.
from pprint import pprint
data = '''\
abc/pqr123/xy2/yes//T
abc/pqr245/kl3/yes//T
abc/ijk123/op5/yes//T
abc/pqr245/kl4/yes//T
'''.splitlines()
nested_dict = {}
for row in data:
d = nested_dict
keys = [s for s in row.split('/') if s]
for key in keys[:-1]:
d = d.setdefault(key, {})
d[keys[-1]] = []
pprint(nested_dict)
output
{'abc': {'ijk123': {'op5': {'yes': {'T': []}}},
'pqr123': {'xy2': {'yes': {'T': []}}},
'pqr245': {'kl3': {'yes': {'T': []}}, 'kl4': {'yes': {'T': []}}}}}

How to iterate through dict values containing lists and remove items?

Python novice here. I have a dictionary of lists, like so:
d = {
1: ['foo', 'foo(1)', 'bar', 'bar(1)'],
2: ['foobaz', 'foobaz(1)', 'apple', 'apple(1)'],
3: ['oz', 'oz(1)', 'boo', 'boo(1)']
}
I am trying to figure out how to loop through the keys of the dictionary and the corresponding list values and remove all strings in each in list with a parantheses tail. So far this is what I have:
for key in keys:
for word in d[key]...: # what else needs to go here?
regex = re.compile('\w+\([0-9]\)')
re.sub(regex, '', word) # Should this be a ".pop()" from list instead?
I would like to do this with a list comprehension, but as I said, I can't find much information on looping through dict keys and corresponding dict value of lists. What's the most efficient way of setting this up?
You can re-build the dictionary, letting only elements without parenthesis through:
d = {k:[elem for elem in v if not elem.endswith(')')] for k,v in d.iteritems()}
temp_dict = d
for key, value is temp_dict:
for elem in value:
if temp_dict[key][elem].find(")")!=-1:
d[key].remove[elem]
you can't edit a list while iterating over it, so you create a copy of your list as temp_list and if you find parenthesis tail in it, you delete corresponding element from your original list.
Alternatively, you can do it without rebuilding the dictionary, which may be preferable if it's huge...
for k, v in d.iteritems():
d[k] = filter(lambda x: not x.endswith(')'), v)

Categories