This question is a continuation of this one: Comprehension list and output <generator object.<locals>.<genexpr> at 0x000002C392688C78>
I was oriented to create a new question.
I have a few dicts inside another dict. And they get pretty big sometimes, since I'm keeping them in log I would like to limit the size of them to 30 'items' (key:value).
So I tried something like this: (In the example I limit the size to two)
main_dict = {
'A':{
'a1': [1,2,3],
'a2': [4,5,6]
},
'B': {
'b1': [0,2,4],
'b2': [1,3,5]
}
}
print([main_dict[x][i][:2] for x in main_dict.keys() for i in main_dict[x].keys()])
The output I get is this:
[[1, 2], [4, 5], [0, 2], [1, 3]]
What I expected was this:
['A':['a1':[1, 2],'a2':[4, 5]], 'B':['b1':[0, 2], 'b2':[1, 3]]]
Or something like that. It doesn't have to be exactly that, but I need to know what value belongs to what dict, which isn't clear in the output I end up getting.
To put it simple all I want is to cut short the sub-dicts inside the dictionary. Elegantly, if possible.
This is a nice clean way to do it in one line, without altering the original dictionary:
print({key: {sub_k: ls[:2] for sub_k, ls in sub_dict.items()} for key, sub_dict in main_dict.items()})
Output:
{'A': {'a1': [1, 2], 'a2': [4, 5]}, 'B': {'b1': [0, 2], 'b2': [1, 3]}}
Your original trial used list comprehension [], but this case actually needs dict comprehension {}.
Try this:
print({key: {sub_key: lst[:2] for sub_key, lst in sub_dict.items()}
for key, sub_dict in main_dict.items()})
Note the use of {} (dict comprehension) instead of [] (list comprehension)
A more efficient approach is to use nested for loops to delete the tail end of the sub-lists in-place:
for d in main_dict.values():
for k in d:
del d[k][2:]
main_dict becomes:
{'A': {'a1': [1, 2], 'a2': [4, 5]}, 'B': {'b1': [0, 2], 'b2': [1, 3]}}
d = {'A':{
'a1': [1,2,3],
'a2': [4,5,6],
'a3': [7,8,9]
},
'B':{
'b1': [0,2,4],
'b2': [1,3,5]
}
}
If the dictionaries are only nested one-deep
q = []
for k,v in d.items():
keys, values = v.keys(), v.values()
values = (value[:2] for value in values)
q.append((k,tuple(zip(keys,values))))
I have rewrote my code based on the comments provided. See below.
my_dict = {}
for key, value in main_dict.iteritems():
sub_dict = {}
for sub_key, sub_value in value.iteritems():
sub_dict[sub_key] = sub_value[:2]
my_dict[key] = sub_dict
print my_dict
This will give you something that looks like this, and save it to a separate variable.
{'A': {'a1': [1, 2], 'a2': [4, 5]}, 'B': {'b1': [0, 2], 'b2': [1, 3]}}
Related
key_list = ['a', 'b']
value_list = [[1, 2], [3, 4],...]
res = [dict(zip(key_list, item)) for item in value_list]
print(res) # [{'a': 1, 'b': 2}, {'a': 3, 'b': 4}, ...]
code as above can get what I want (list of dict element): [{'a': 1, 'b': 2}, {'a': 3, 'b': 4}, ...]
but I think this maybe not effective way.
Is there some more effective method to transfer?
If you only need to iterate through res sequentially and it is made from huge lists you could use:
res = (dict(zip(key_list, item)) for item in value_list)
(Note the round parenthesis), this will create the pairs one by one as you request them. Keep in mind that with this way you will only be able to iterate over res once and you will not be able to index it.
I currently have the following:
mydict = {'a': [1, 2, 3], 'b': [1, 2]}
I want to return a string containing quantities of items available in the dictionary. For example
a: 3
b: 2
However, I want my output to update if I add another key value pair to the dictionary. For example mydict['c'] = [1, 2, 3]
I have thought about how to do this and this is all that comes to mind:
def quantities() -> str:
mydict = {'a': [1, 2, 3], 'b': [1, 2]}
for k, v in mydict:
print(f'{k}: {len(v)})
But I am not sure if this is correct. Are there any other ways to do this.
The statement:
for <variable> in mydict:
Iterates through only the keys of the dictionary. So, you can either use the key to get the item like:
mydict = {'a': [1, 2, 3], 'b': [1, 2]}
for k in mydict:
print(f'{k}: {len(mydict[k])}')
Or use mydict.items() This makes it iterate through every (key, value). USe it as:
mydict = {'a': [1, 2, 3], 'b': [1, 2]}
for k, v in mydict.items():
print(f'{k}: {len(v)}')
I don't think your sample code will work. I used this documentation and use sorted() I think what you want is something like this.
mydict = {'a': [1, 2, 3, 4], 'b': [1, 2]}
def quantities():
for k, v in sorted(mydict.items()):
print(k, len(v))
quantities()
You can do this with str.join and a generator expression:
def quantities(mydict):
return '\n'.join('{}: {}'.format(k, len(v)) for k, v in mydict.items())
Looking for a way to add two lists to a value in a dictionary for example if want to add two lists to a single value for example
For example this dictionary dict1 = {a: [], b:[], c:[]}
Would become dict1 = {a:([1,3,4,5,6],[1,2,3,4]),b:[],c:[]}
When you add the two lists [1,2,3,4,5,6] and [1,2,3,4] to the key a.
And if you were to print the key a you would get the two lists as output
Any help would be much appreciated
You can use list.append() because your dict1['a']'s value is a list. See this example:
dict1 = {'a': [], 'b':[], 'c':[]}
a = [1,2,3,4,5,6]
b = [1,2,3,4]
dict1['a'].append(a)
dict1['a'].append(b)
print(dict1)
Output:
{'a': [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4]], 'b': [], 'c': []}
you can also doing it in this way by adding two list [a]+[b]
Edit: from the comment. Another better way [a,b]
dict1 = {'a': [], 'b':[], 'c':[]}
a = [1,2,3,4,5,6]
b = ['a','b']
dict1['a']=[a]+[b]
print(dict1)
What is the pythonic way to iterate over a dictionary with a setup like this:
dict = {'a': [1, 2, 3], 'b': [3, 4, 5], 'c': 6}
if I only wanted to iterate a for loop over all the values in a and b and skip c. There's obviously a million ways to solve this but I'd prefer to avoid something like:
for each in dict['a']:
# do something
pass
for each in dict['b']:
# do something
pass
of something destructive like:
del dict['c']
for k,v in dict.iteritems():
pass
The more generic way is using filter-like approaches by putting an if in the end of a generator expression.
If you want to iterate over every iterable value, filter with hasattr:
for key in (k for k in dict if hasattr(dict[k], '__iter__')):
for item in dict[key]:
print(item)
If you want to exclude some keys, use a "not in" filter:
invalid = set(['c', 'd'])
for key in (k for k in dict if key not in invalid):
....
If you want to select only specific keys, use a "in" filter:
valid = set(['a', 'b'])
for key in (k for k in dict if key in valid):
....
Similar to SSDMS's solution you can also just do:
mydict = {'a': [1, 2, 3], 'b': [3, 4, 5], 'c': 6}
for each in mydict['a']+mydict['b']:
....
You can use chain from the itertools module to do this:
In [29]: from itertools import chain
In [30]: mydict = {'a': [1, 2, 3], 'b': [3, 4, 5], 'c': 6}
In [31]: for item in chain(mydict['a'], mydict['b']):
...: print(item)
...:
1
2
3
3
4
5
To iterate over only the values the keys' value in the dictionary that are instance of list simply use chain.from_iterable.
wanted_key = ['a', 'b']
for item in chain.from_iterable(mydict[key] for key in wanted_key if isinstance(mydict[key], list)):
# do something with the item
How do I build a dict using list comprehension?
I have two lists.
series = [1,2,3,4,5]
categories = ['A', 'B', 'A', 'C','B']
I want to build a dict where the categories are the keys.
Thanks for your answers I'm looking to produce:
{'A' : [1, 3], 'B' : [2, 5], 'C' : [4]}
Because the keys can't exist twice
You have to have a list of tuples. The tuples are key/value pairs. You don't need a comprehension in this case, just zip:
dict(zip(categories, series))
Produces {'A': 3, 'B': 5, 'C': 4} (as pointed out by comments)
Edit: After looking at the keys, note that you can't have duplicate keys in a dictionary. So without further clarifying what you want, I'm not sure what solution you're looking for.
Edit: To get what you want, it's probably easiest to just do a for loop with either setdefault or a defaultdict.
categoriesMap = {}
for k, v in zip(categories, series):
categoriesMap.setdefault(k, []).append(v)
That should produce {'A': [1, 3], 'B': [2, 5], 'C': [3]}
from collectons import defaultdict
series = [1,2,3,4,5]
categories = ['A', 'B', 'A', 'C','B']
result = defaultdict(list)
for key, val in zip(categories, series)
result[key].append(value)
Rather than being clever (I have an itertools solution I'm fond of) there's nothing wrong with a good, old-fashioned for loop:
>>> from collections import defaultdict
>>>
>>> series = [1,2,3,4,5]
>>> categories = ['A', 'B', 'A', 'C','B']
>>>
>>> d = defaultdict(list)
>>> for c,s in zip(categories, series):
... d[c].append(s)
...
>>> d
defaultdict(<type 'list'>, {'A': [1, 3], 'C': [4], 'B': [2, 5]})
This doesn't use a list comprehension because a list comprehension is the wrong way to do it. But since you seem to really want one for some reason: how about:
>> dict([(c0, [s for (c,s) in zip(categories, series) if c == c0]) for c0 in categories])
{'A': [1, 3], 'C': [4], 'B': [2, 5]}
That has not one but two list comprehensions, and is very inefficient to boot.
In principle you can do as Kris suggested: dict(zip(categories, series)), just be aware that there can not be duplicates in categories (as in your sample code).
EDIT :
Now that you've clarified what you intended, this will work as expected:
from collections import defaultdict
d = defaultdict(list)
for k, v in zip(categories, series):
d[k].append(v)
d={ k:[] for k in categories }
map(lambda k,v: d[k].append(v), categories, series )
result:
d is now = {'A': [1, 3], 'C': [4], 'B': [2, 5]}
or (equivalent) using setdefault (thanks Kris R.)
d={}
map(lambda k,v: d.setdefault(k,[]).append(v), categories, series )