Python - intersection between list and dict keys - python

I have this list:
list1 = [{'Hello'}, {'Welcome'}, {'BYE'}]
And I have a dictionary:
dict1 = {'Welcome': 5, 'BYE': 3, 'How are you': 3}
I would like the result to be something like:
dict2 = {'Welcome': 5, 'BYE': 3}
According to this post.
I tried:
dict2 = {k: dict1[k] for k in (dict1.keys() & list1)}
But it says:
TypeError: unhashable type: 'set'
Do I need first to make list1, like this:
list1 = ['Hello', 'Welcome', 'BYE']
And if this is the problem, then how?

You can make a set of value from the list1:
list1 = [{"Hello"}, {"Welcome"}, {"BYE"}]
dict1 = {"Welcome": 5, "BYE": 3, "How are you": 3}
dict2 = {k: dict1[k] for k in (dict1.keys() & {v for s in list1 for v in s})}
print(dict2)
Prints:
{'BYE': 3, 'Welcome': 5}

If you are required to start with that weird single-item-set-in-list list, I'd flatten it with itertools.chain.from_iterable into a simple list. From there, with a simple dictionary comprehension, you create a new dictionary for each key from list1 that exists in dict1:
>>> from itertools import chain
>>> list1 = [{'Hello'}, {'Welcome'}, {'BYE'}]
>>> dict1 = {'Welcome': 5, 'BYE': 3, 'How are you': 3}
>>> list(chain.from_iterable(list1))
['Hello', 'Welcome', 'BYE']
>>> {k: dict1[k] for k in chain.from_iterable(list1) if k in dict1}
{'Welcome': 5, 'BYE': 3}

Yes your variable list1 is a list of set, you might do this:
dict2 = {k: dict1[k] for k in set(dict1.keys()).intersection(set().union(*list1))}

Related

removing all the keys with the same value in dictionary

I want to get a new dictionary by removing all the keys with the same value (keys are differents, values are the same)
For example: Input:
dct = {'key1' : [1,2,3], 'key2': [1,2,6], 'key3': [1,2,3]}
expected output:
{'key2': [1, 2, 6]}
key1 and key3 was deleted because they shared same values.
I have no idea about it?
You can do this by creating a dictionary based on the values. In this case the values are lists which are not hashable so convert to tuple. The values in the new dictionary are lists to which we append any matching key from the original dictionary. Finally, work through the new dictionary looking for any values where the list length is greater than 1 - i.e., is a duplicate. Then we can remove those keys from the original dictionary.
d = {'key1' : [1,2,3], 'key2': [1,2,6], 'key3': [1,2,3]}
control = {}
for k, v in d.items():
control.setdefault(tuple(v), []).append(k)
for v in control.values():
if len(v) > 1:
for k in v:
del d[k]
print(d)
Output:
{'key2': [1, 2, 6]}
I created a list of counts which holds information about how many times an item is in the dictionary. Then I copy only items which are there once.
a = {"key1": [1,2,3], "key2": [1,2,6], "key3": [1,2,3]}
# find how many of each item are there
counts = list(map(lambda x: list(a.values()).count(x), a.values()))
result = {}
#copy only items which are in the list once
for i,item in enumerate(a):
if counts[i] == 1:
result[item] = a[item]
print(result)
As given by the OP, the simplest solution to the problem:
dct = {'key1' : [1,2,3], 'key2': [1,2,6], 'key3': [1,2,3]}
print({k:v for k, v in dct.items() if list(dct.values()).count(v) == 1})
Output:
{'key2': [1, 2, 6]}
One loop solution:
dict_ = {'key1' : [1,2,3], 'key2': [1,2,6], 'key3': [1,2,3]}
key_lookup = {}
result = {}
for key, value in dict_.items():
v = tuple(value)
if v not in key_lookup:
key_lookup[v] = key
result[key] = value
else:
if key_lookup[v] is not None:
del result[key_lookup[v]]
key_lookup[v] = None
print(result)
Output:
{'key2': [1, 2, 6]}
dct = {'key1' : [1,2,3], 'key2': [1,2,6], 'key3': [1,2,3]}
temp = list(dct.values())
result = {}
for key, value in dct.items():
for t in temp:
if temp.count(t) > 1:
while temp.count(t) > 0:
temp.remove(t)
else:
if t == value:
result[key] = value
print(result)
Output:
{'key2': [1, 2, 6]}

Count values with items in a dictionary with sublists

I'n being warned that this question has been frequently downvoted, but I haven't seen a solution for my particular problem.
I have a dictionary that looks like this:
d = {'a': [['I', 'said', 'that'], ['said', 'I']],
'b':[['she', 'is'], ['he', 'was']]}
I would like for the output to be a dictionary with the original keys and then a dictionary containing a value that indicates the count for each of the words (e.g., {'a':{'I':2, 'said':2, 'that':1} and so on with b.
If the values were in a list instead of a sublist, I could get what I wanted just by using Counter:
d2 = {'a': ['I','said','that', 'I'],'b': ['she','was','here']}
from collections import Counter
counts = {k: Counter(v) for k, v in d2.items()}
However, I'm getting TypeError: unhashable type: 'list' because the lists containing the values I want to count are sublists and the list that contains them isn't hashable.
I also know that if I just had sublists, I could get what I want with something like:
lst = [['I', 'said', 'that'], ['said', 'I']]
Counter(word for sublist in lst for word in sublist)
But I just can't figure out how to combine these ideas to solve my problem (and I guess it lies in combining these two).
I did try this
for key, values in d.items():
flat_list = [item for sublist in values for item in sublist]
new_dict = {key: flat_list}
counts = {k: Counter(v) for k, v in new_dict.items()}
But that only gives me the counts for the second list (because the flat_list itself only returns the value for the second key.
To combine the two solutions, just replace Counter(v) from your first solution with the second solution.
from collections import Counter
d = {'a': [['I', 'said', 'that'], ['said', 'I']],
'b': [['she', 'is'], ['he', 'was']]}
counts = {k: Counter(word
for sublist in lst
for word in sublist)
for k, lst in d.items()}
print(counts)
Output:
{'a': Counter({'I': 2, 'said': 2, 'that': 1}),
'b': Counter({'she': 1, 'is': 1, 'he': 1, 'was': 1})}
You can merge your sublists to get your d2: d2 = {k: reduce(list.__add__, d[k], []) for k in d}.
In python3, you will need to from functools import reduce
Use both itertools and collections modules for this. Flatten the nested lists with itertools.chain and count with collections.Counter
import itertools, collections
d = {
'a': [['I', 'said', 'that'], ['said', 'I']],
'b':[['she', 'is'], ['he', 'was']]
}
out_dict = {}
for d_key, data in d.items():
counter = collections.Counter(itertools.chain(*data))
out_dict[d_key] = counter
print out_dict
Output:
{'a': Counter({'I': 2, 'said': 2, 'that': 1}),
'b': Counter({'she': 1, 'is': 1, 'he': 1, 'was': 1})}

how can I manipulate key with for loops to update dictionary

I am trying to put a list into a dictionary and count the number of occurrences of each word in the list. The only problem I don't understand is when I use the update function, it takes x as a dictionary key, when I want x to be the x value of list_ . I am new to python so any advice is appreciated. Thanks
list_ = ["hello", "there", "friend", "hello"]
d = {}
for x in list_:
d.update(x = list_.count(x))
Use a Counter object if you want a simple way of converting a list of items to a dictionary which contains a mapping of list_entry: number_of_occurences .
>>> from collections import Counter
>>> words = ['hello', 'there', 'friend', 'hello']
>>> c = Counter(words)
>>> print(c)
Counter({'hello': 2, 'there': 1, 'friend': 1})
>>> print(dict(c))
{'there': 1, 'hello': 2, 'friend': 1}
An option would be using dictionary comprehension with list.count() like this:
list_ = ["hello", "there", "friend", "hello"]
d = {item: list_.count(item) for item in list_}
Output:
>>> d
{'hello': 2, 'there': 1, 'friend': 1}
But the best option should be collections.Counter() used in #AK47's solution.

Python3 dictionary merge based on values

I have a dictionary composed of {key: value}.
I select a set of keys from this dictionary.
I'd like to build a new dictionary with {keyA: set of all keys wich have the same value as keyA}.
I already have a solution: Is there a faster way to do it?
It seems very slow to me, and I imagine I'm not the only one in this case!
for key1 in selectedkeys:
if key1 not in seen:
seen.add(key1)
equal[key1] = set([key1])#egual to itself
for key2 in selectedkeys:
if key2 not in seen and dico[key1] == dico[key2]:
equal[key1].add(key2)
seen.update(equal[key1])
Try this
>>> a = {1:1, 2:1, 3:2, 4:2}
>>> ret_val = {}
>>> for k, v in a.iteritems():
... ret_val.setdefault(v, []).append(k)
...
>>> ret_val
{1: [1, 2], 2: [3, 4]}
def convert(d):
result = {}
for k, v in d.items(): # or d.iteritems() if using python 2
if v not in result:
result[v] = set()
result[v].add(k)
return result
or just use collections.defaultdict(set) if you are careful enough not to access any non key later :-)
So you want to create a dictionary that maps key to "the set of all keys which have the same value as key" for each selected key in a given source dictionary.
Thus, if the source dictionary is:
{'a': 1, 'b': 2, 'c': 1, 'd': 2, 'e': 3, 'f': 1, 'g': 3)
and the selected keys are a, b, and e, the result should be:
{'a': {'a', 'c', 'f'}, 'e': {'g', 'e'}, 'b': {'b', 'd'}}
One way to achieve this would be to use a defaultdict to build a value to key table, and then use that to build the required result from the specified keys:
from collections import defaultdict
def value_map(source, keys):
table = defaultdict(set)
for key, value in source.items():
table[value].add(key)
return {key: table[source[key]] for key in keys}
source = {'a': 1, 'b': 2, 'c': 1, 'd': 2, 'e': 3, 'f': 1, 'g': 3)
print(value_map(source, ['a', 'b', 'e']))
Output:
{'a': {'a', 'c', 'f'}, 'e': {'g', 'e'}, 'b': {'b', 'd'}}
Since you select a set of keys from the original dictionary. We can modify #Nilesh solution for your purpose.
a = {1:1, 2:1, 3:2, 4:2}
keys = [1, 3] # lets say this is the list of keys
ret_val = {}
for i in keys:
for k,v in a.items():
if a[i]==v:
ret_val.setdefault(i, []).append(k)
print (ret_val)
{1: [1, 2], 3: [3, 4]}
This was sort of stated in the comments by #Patrick Haugh:
d=your dictionary
s=set(d.values())
d2={i:[] for i in s}
for k in d:
d2[d[k]].append(k)

How to add in a dictionary the values that have similar keys?

I would like to add together the values from a dictionary in Python, if their keys begin with the same letter..
For example, if I have this dictionary: {'apples': 3, 'oranges': 5, 'grapes': 4, 'apricots': 2, 'grapefruit': 9}
The result would be: {'A': 5,'G': 13, 'O': 5}
I only got this far and I'm stuck:
for k in dic.keys():
if k.startswith('A'):
Any help will be appreciated
Take the first character of each key, call .upper() on that and sum your values by that uppercased letter. The following loop
out = {}
for key, value in original.iteritems():
out[key[0].upper()] = out.get(key[0].upper(), 0) + value
should do it.
You can also use a collections.defaultdict() object to simplify that a little:
from collections import defaultdict:
out = defaultdict(int)
for key, value in original.iteritems():
out[key[0].upper()] += value
or you could use itertools.groupby():
from itertools import groupby
key = lambda i: i[0][0].upper()
out = {key: sum(v for k, v in group) for key, group in groupby(sorted(original.items(), key=key), key=key)}
You can use a defaultdict here:
from collections import defaultdict
new_d = defaultdict(int)
for k, v in d.iteritems():
new_d[k[0].upper()] += v
print new_d
Prints:
defaultdict(<type 'int'>, {'A': 5, 'O': 5, 'G': 13})
Lots of ways to do this. Here's a variant using Counter that nobody else has suggested and unlike Ashwini's solution it doesn't create potentially long intermediate strings:
>>> from collections import Counter
>>> dic = {'apples': 3, 'oranges': 5, 'grapes': 4, 'apricots': 2, 'grapefruit': 9}
>>> sum((Counter({k[0].upper():dic[k]}) for k in dic), Counter())
Counter({'G': 13, 'A': 5, 'O': 5})

Categories