Python: how to search within a homogenous values dictionary - python

I have this dictionary:
dict = {'a': [1, 'Hello', 3], 'b': {1, 2, 90}, 'c': (1, 2, 'tuple'), 'd': 3}
I tried to print each key contains the value 3. The output has to be a and d
I tired something like this:
[key for key, vals in dict.items() if 3 in vals]
but an error: int is not iterable
I also tried to use for :
>>> for i in dict.values():
... if 3 in dict.values():
... print(i)
I also tried this but nothing works
>>> for i in dict.keys():
... if 3 in dict[i]:
... print(i)
PART 2: Let us say I am able to print the key if the value contains 3, then how can I get the index if the value is list or tuple?

[key for key, vals in dict.items() if 3==vals or 3 in vals]

The error you get is because not all your values are of the same type.
Your evaluation needs to be if key equals to 3 then return true, or if the value is a container, check if 3 is part of it.
To get an index of a value in a list OR a tuple, you can use
>>> l = [1, 2, 'just', 3, 'p']
>>> l.index(3)
3
>>> t = (1, 2, 'word', 3)
>>> t.index(3)
3
>>>

for k, v in dict.items():
try:
if 3 in v:
print(k)
except TypeError:
if v == 3:
print(k)

Another way is to test if the value of the key is not scalar, before trying to use in:
def in_key(value, vals):
if isinstance(vals, (list, tuple, set)):
return value in vals
else:
return value == vals
lst = [key for key, vals in dict.items() if in_vals(3, vals)]

Your code is almost right, just check the item equal or contained in a set of vals:
dict = {'a': [1, 'Hello', 3], 'b': {1, 2, 90}, 'c': (1, 2, 'tuple'), 'd': 3}
print [key for key, vals in dict.items() if 3 == vals or 3 in vals]
['a', 'd']
Here you have a live example

Related

How do I count each unique value for each key in a dictionary containing lists?

I have the following dictionary:
dict = {'A': [1,1,2], 'B': [1,1,1], 'C': [2,2,2,1,2]}
I want the output to tell me how many of each values I have for each key, e.g.:
if value == 1 -> A, 2; B,3; C,1
if value == 2 -> A, 1; B,0; C,4
So far I have:
for i in dict[i]:
if i == 1:
participants_luck += 1
elif i == 2:
participants_skill += 1
This is a flexible solution to count the occurrences of each different value in the dictionary
dict = {"A": [1,1,2], "B": [1,1,1], "C": [2,2,2,1,2]}
different_values = set()
for values in dict.values():
for el in values:
different_values.add(el)
for possible_value in different_values:
print(possible_value)
for key, values in dict.items():
print(key, sum(value == possible_value for value in values))
print("\n")
Output:
1
A 2
B 3
C 1
2
A 1
B 0
C 4
UPDATE: If you want to handle also non list items in dict you can do like this:
from collections.abc import Iterable
dict = {"A": [1,1,2], "B": [1,1,1], "C": [2,2,2,1,2], "D": 1}
different_values = set()
for values in dict.values():
if isinstance(values, Iterable):
for el in values:
different_values.add(el)
else:
different_values.add(values)
for possible_value in different_values:
print(possible_value)
for key, values in dict.items():
if isinstance(values, Iterable):
print(key, sum(value == possible_value for value in values))
else:
print(key, int(values == possible_value))
print("\n")
And the output will be:
1
A 2
B 3
C 1
D 1
2
A 1
B 0
C 4
D 0
Define a function so you can search for different values if you ever need to. Use the count method to make things very easy for yourself.
d = {'A': [1,1,2], 'B': [1,1,1], 'C': [2,2,2,1,2]}
def foo(value, dictionary):
for key,l in dictionary.items():
print(f"{key} : {l.count(value)}")
foo(1,d)
foo(2,d)
This is a one-liner! You can write a dictionary comprehension. We have a dictionary mydict and a value to count. We first iterate over the items in the dictionary. For each list in the dictionary, we iterate over that list, and find the sum of i == value. Because True counts as 1 and False counts as 0, sum(i == value for i in lst) will give the number of i in the lst which are equal to value. Alternatively, you could do lst.count(value). The sum(...) technique is useful when you want to count a condition other than ==, for example if you wanted to count how many elements are less than the given value.
def count(mydict, value):
return {k: sum(i == value for i in lst) for k, lst in mydict.items()}
# Or,
# return {k: lst.count(value) for k, lst in mydict.items()}
d = {'A': [1,1,2], 'B': [1,1,1], 'C': [2,2,2,1,2]}
count(d, 1) # out: {'A': 2, 'B': 3, 'C': 1}
count(d, 2) # out: {'A': 1, 'B': 0, 'C': 4}
You can then access the counts like so:
result = count(d, 1)
print(f"A: {result['A']}, B: {result['B']}, C: {result['C']}")
Or, if you don't want to hardcode the keys of result:
result = count(d, 1)
for k, v in result.items():
print(f"{k}: {v}")
You could use a Counter:
from collections import Counter
cnts={k: Counter(v) for k,v in di.items()}
# {'A': Counter({1: 2, 2: 1}), 'B': Counter({1: 3}), 'C': Counter({2: 4, 1: 1})}
Then just use a comprehension to get the sub counts as needed:
>>> {k:v[1] for k,v in cnts.items()}
{'A': 2, 'B': 3, 'C': 1}
>>> ({k:v[2] for k,v in cnts.items()}
{'A': 1, 'B': 0, 'C': 4}
Would be interesting making a function to do it.
def count_stuff(any_dict, wanted_val):
counted_dict = {}
for key in any_dict.keys():
count = 0
for element in any_dict[key]:
count += (element == wanted_val)
counted_dict[key] = count
return counted_dict
Running your example...
your_dict = {"A": [1,1,2], "B": [1,1,1], "C": [2,2,2,1,2]}
for i in [1, 2]:
print(i, count_stuff(your_dict, i))
Prints
1 {'A': 2, 'B': 3, 'C': 1}
2 {'A': 1, 'B': 0, 'C': 4}

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

iterate over only two keys of python dictionary

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

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

Iterating Over a Dictionary

I am trying to return all the values in a dictionary that have a value greater than the int argurment.
def big_keys(dict, int):
count = []
for u in dict:
if u > int:
count.append(u)
return count
I don't understand why this isn't working. It returns every value in the list rather than just those which are greater than in.
By default, any dict will iterate over its keys, not its values:
>>> d = {'a': 1, 'b': 2}
>>> for i in d:
... print i
...
a
b
To iterate over values, use .values():
>>> for i in d.values():
... print i
...
1
2
With that in mind, your method can be simplified:
def big_keys(d, i):
return [x for x in d.values() if x > i]
I have changed your variable names, since dict and int are both built-ins.
Your method is actually recreating default functionality available in Python. The filter method does what you are trying to do:
>>> d = {'a': 1, 'b': 6, 'd': 7, 'e': 0}
>>> filter(lambda x: x > 5, d.values())
[6, 7]
From your comment it seems you are looking for the keys and not the values. Here is how you would do that:
>>> d = {'a': 21, 'c': 4, 'b': 5, 'e': 30, 'd': 6, 'g': 4, 'f': 2, 'h': 20}
>>> result = []
>>> for k,v in d.iteritems():
... if v > 20:
... result.append(k)
...
>>> result
['a', 'e']
Or, the shorter way:
>>> [k for k,v in d.iteritems() if v > 20]
['a', 'e']
iterating dictionary yields keys for the dictionary.
>>> d = {'key1': 'value1', 'key2': 'value2'}
>>> for x in d:
... print(x)
...
key2
key1
To get values, use dict.values():
>>> for x in d.values():
... print(x)
...
value2
value1
So, you program should read as follow:
def big_keys(dict, int):
count = []
for u in dict.values():
if u > int:
count.append(u)
return count

Categories

Resources