iterate over only two keys of python dictionary - python

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

Related

How to return a string containing information about how many values exist for each key

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())

How to extract only certain values from a dictionary (python)

Let's say that I have a list l=[1, 2, 3, 4] and a dictionary d={2:a, 4:b}.
I'd like to extract the values of d only in the key is also in my list and put the result in a new list.
This is what I've tried so far:
new_l=[]
for i in l:
for key in d.keys():
if key in l:
new_l.append(d[key])
print (new_l)
Thank you in advance for your help.
This will compare each value in the dictionary and if it's match in the list.
Simplistic answer..
>>> l
[1, 2, 3, 4]
>>> d
{2: 'a', 4: 'b'}
>>> [value for (key,value) in d.items() if key in l]
['a', 'b']
You don't need to cycle through each key in that second for loop. With Python, you can just use a list comprehension:
L = [1, 2, 3, 4]
d = {2: 'a', 4: 'b'}
res = [d[i] for i in L if i in d] # ['a', 'b']
An alternative functional solution is possible if you know your dictionary values are non-Falsy (e.g. not 0, None). filter is a lazy iterator, so you'll need to exhaust via list in a subsequent step:
res = filter(None, map(d.get, L))
print(list(res)) # ['a', 'b']
You can skip iterating l
Ex:
l=[1, 2, 3, 4]
d={2:"a", 4:"b"}
new_l=[]
for key in d.keys():
if key in l:
new_l.append(d[key])
print (new_l)
Iterate the dictionary with key and match the key present in list.
L=[1, 2, 3, 4]
d={2:"a", 4:"b"}
new_l=[]
for k in d.keys():
if k in L:
new_l.append(d[k])
print (new_l)

Python nested dict comprehension

I have a dictionary:
my_dict = {'a': [1, 2, 3], 'c': 3, 'b': 2}
And I want a comprehension like add_dict = (x x +1 for x my_dict)
what would be the best approach to take when writing a comprehension to deal with keys with multiple values?
So the output would look like {'a': [2, 3, 4], 'c': 4, 'b':3} or maybe I might want to only +1 to values 1 and 2 of each key, keys 'b' and 'c' ... would be skipped.
I tried this (first two lines are kind redundant / was messing about)
my_dict = {'a': [1, 2, 3], 'b': 2, 'c': 3}
D = {x: y for (x, y) in zip(my_dict.keys(), my_dict.values())}
test = (v for v in D.values())
for x in test:
try:
if len(x):
for i in x:
print i +1
except:
print x +1
if name == 'main':
main()
output was
2
3
4
object of type 'int' has no len()
object of type 'int' has no len()
I was trying to find a more elegant way of doing this that worked using comprehensions.
Here's a one-liner for you (in Python 3), assuming the dictionary values never become double-nested:
>>> {k:([x+1 for x in v] if not isinstance(v,int) else v+1) for k,v in my_dict.items()}
{'a': [2, 3, 4], 'b': 3, 'c': 4}
Replace my_dict.items() with my_dict.iteritems() for Python 2

Merge dictionaries retaining values for duplicate keys [duplicate]

This question already has answers here:
How to merge dicts, collecting values from matching keys?
(17 answers)
Closed 12 days ago.
Given n dictionaries, write a function that will return a unique dictionary with a list of values for duplicate keys.
Example:
d1 = {'a': 1, 'b': 2}
d2 = {'c': 3, 'b': 4}
d3 = {'a': 5, 'd': 6}
result:
>>> newdict
{'c': 3, 'd': 6, 'a': [1, 5], 'b': [2, 4]}
My code so far:
>>> def merge_dicts(*dicts):
... x = []
... for item in dicts:
... x.append(item)
... return x
...
>>> merge_dicts(d1, d2, d3)
[{'a': 1, 'b': 2}, {'c': 3, 'b': 4}, {'a': 5, 'd': 6}]
What would be the best way to produce a new dictionary that yields a list of values for those duplicate keys?
Python provides a simple and fast solution to this: the defaultdict in the collections module. From the examples in the documentation:
Using list as the default_factory, it is easy to group a sequence of
key-value pairs into a dictionary of lists:
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
... d[k].append(v)
...
>>> d.items()
[('blue', [2, 4]), ('red', 1), ('yellow', [1, 3])]
When each key is encountered for the first time, it is not already in
the mapping; so an entry is automatically created using the
default_factory function which returns an empty list. The
list.append() operation then attaches the value to the new list. When
keys are encountered again, the look-up proceeds normally (returning
the list for that key) and the list.append() operation adds another
value to the list.
In your case, that would be roughly:
import collections
def merge_dicts(*dicts):
res = collections.defaultdict(list)
for d in dicts:
for k, v in d.iteritems():
res[k].append(v)
return res
>>> merge_dicts(d1, d2, d3)
defaultdict(<type 'list'>, {'a': [1, 5], 'c': [3], 'b': [2, 4], 'd': [6]})
def merge_dicts(*dicts):
d = {}
for dict in dicts:
for key in dict:
try:
d[key].append(dict[key])
except KeyError:
d[key] = [dict[key]]
return d
This retuns:
{'a': [1, 5], 'b': [2, 4], 'c': [3], 'd': [6]}
There is a slight difference to the question. Here all dictionary values are lists. If that is not to be desired for lists of length 1, then add:
for key in d:
if len(d[key]) == 1:
d[key] = d[key][0]
before the return d statement. However, I cannot really imagine when you would want to remove the list. (Consider the situation where you have lists as values; then removing the list around the items leads to ambiguous situations.)

How do I build a dict using list comprehension?

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 )

Categories

Resources