I have a dictionary of numbers to lists of numbers like:
a = { 1: [2,3,4] , 2: [1,4] }
i want to create a new dictionary with comprehension based on it where each element from each list would be linked to the key to that list.
That would be something like:
b = { element : [key] for key in a.keys() for element in a[key]}
that gives me of course:
b = {1: [2], 2: [1], 3: [1], 4: [2]}
instead of
b = {1: [2], 2: [1], 3: [1], 4: [1,2]}
because the index gets overwritten. so I need to do something like:
b = { element : [key] + self[element] for key in a.keys() for element in a[key]}
or
b = { element +: key for key in a.keys() for element in a[key]}
but in a working fashion.
Is it possible?
It's easy to build your dictionary using defaultdict and two loops.
from collections import defaultdict
a = { 1: [2,3,4] , 2: [1,4] }
b = defaultdict(list)
for key, value in a.iteritems():
for elem in value:
b[elem].append(key)
im assuming this is for some form of mapping:
from itertools import chain
def makeMap(d):
nodes = set([x for x in chain.from_iterable(d.values())])
return dict([[x, [y for y in d.keys() if x in d[y]]] for x in nodes ])
this code will do that for you :)
EDIT:
and heres the (massive) one liner, I wouldn't recommend putting this in code though, since it's unreadable.
def makeMap(d):
return dict([[x, [y for y in d.keys() if x in d[y]]]
for x in set([x for x in chain.from_iterable(d.values())])
])
steps:
1. make a set of all the possible node values
2. find all the node values in the dictionary values, if there then put the key it was found in into the mapped to list.
Everything is possible:
>>> a = { 1: [2,3,4] , 2: [1,4] }
>>> d={}
>>> for k, v in sum(map(lambda x: zip(x[1], [x[0]]*len(x[1])), a.items()), []):
... d.setdefault(k, []).append(v)
...
>>> d
{1: [2], 2: [1], 3: [1], 4: [1, 2]}
>>>
Related
I have a dictionary
my_dict = {"a":1, "b":2, "c":3}
And list
my_list = [2,3,1]
I want to replace items in my_list with keys from my_dict, something like...
my_list = [b, c, a]
How can i achieve this?
I'm sure it's possible to manufacture a list comprehension but this could be one approach (which only ever iterates over the list once and allows you to cover potential edge cases inside the loop):
for key, value in my_dict.items():
if value not in my_list:
# Does this case need special handling?
continue
index = my_list.index(value)
my_list[index] = key
There are a few edge cases to consider here, e.g. what happens if not all items match, what if the dictionary and list are of unequal lengths etc. Depending on your use case you want to make sure to cover all possible edge cases accordingly.
Applied to your example code, it yields the following output:
>>> my_dict = {"a":1, "b":2, "c":3}
>>> my_list = [2,3,1]
>>> my_dict
{'a': 1, 'b': 2, 'c': 3}
>>> my_list
[2, 3, 1]
>>> for key, value in my_dict.items():
... if value not in my_list:
... # Does this case need special handling?
... continue
... index = my_list.index(value)
... my_list[index] = key
>>> my_list
['b', 'c', 'a']
Dictionaries are mappings. You want to use reverse mappings (use values to find keys), so let's reverse the dict.
my_dict = {"a":1, "b":2, "c":3}
reversed_dict = {my_dict[k]:k for k in my_dict}
Then we just apply the dict to each element:
my_list = [2,3,1]
result = [reversed_dict[elem] for elem in my_list]
You can reverse the key value pair of your dict and then iterate your list to get the corresponding keys.
>>> rev_dict = dict((v,k) for k,v in my_dict.items())
>>> rev_dict
{1: 'a', 2: 'b', 3: 'c'}
>>> [rev_dict[x] for x in my_list]
['b', 'c', 'a']
rev = { v:k for k,v in my_dict.items()}
new_list = [rev[item] for item in my_list]
Output new_list:
['b', 'c', 'a']
This will probably work
for key, val in my_dict.items():
for i, v in enumerate(my_list):
if v == val:
my_list[i] = key
You can do this with list comprehension, what you need to do is: sort the dict.items according to your list, then return the key:
>>> my_dict = {"a":1, "b":2, "c":3}
>>> my_list = [2,3,1]
>>> [key for key, value in sorted(my_dict.items(), key = lambda x:my_list.index(x[1]))]
['b', 'c', 'a']
You can use the function itemgetter. First, you need to swap keys and values in your dictionary:
from operator import itemgetter
dct = {"a": 1, "b": 2, "c": 3}
lst = [2, 3, 1]
dct = {v: k for k, v in dct.items()}
# {1: 'a', 2: 'b', 3: 'c'}
print(list(itemgetter(*lst)(dct)))
# ['b', 'c', 'a']
I have a general list with information:
lis = ["Hello", "Hello1", "Test"]
Then I have a dictionary with filepathes to .c files as values and keys are extensions of the lis values like:
dict1 = {"/****Hello****/":
["C://test/hello/one.c",
"C://test/hello/two.c"],
"/****Hello1****/":
["C://test/helloNext/one.c",
"C://test/helloNext/two.c"],
"/****Test****/":
["C://test/bye/one.c",
"C://test/bye/two.c"]}
The idea is to replace the keys of dict1 with the values of lis, if values of lis are in the key information.
for x in lis:
for y in dict1.copy():
if x in y:
dict1[x] = dict1.pop(y)
As far as good but now I found a big problem:
If I do it that way, some information of dict1 are overwritten because in this example, it searches for a key with "Hello" in it and overwrites dict1[0] but also overwrites dict1[1] to "Hello" instead of "Hello1" because it's the first information...
I don't get to a solution on my own.
I think I am just missing a little bit...
Thanks!
PS: It is not a solution to just cut out special characters from the keys, because it does not look the same for every file..
One way would be to sort the list based on the length of the elements and process it in the reverse order:
lis = ["Hello", "Hello1", "Test"]
dict1 = {"/****Hello****/": ["C://test/hello/one.c", "C://test/hello/two.c"],
"/****Hello1****/": ["C://test/helloNext/one.c", "C://test/helloNext/two.c"],
"/****Test****/": ["C://test/bye/one.c", "C://test/bye/two.c"]}
for x in sorted(lis, key=len, reverse=True):
for y in dict1:
if x in y and y not in lis:
dict1[x] = dict1.pop(y)
break
print(dict1)
# {'Hello1': ['C://test/helloNext/one.c', 'C://test/helloNext/two.c'], 'Hello': ['C://test/hello/one.c', 'C://test/hello/two.c'], 'Test': ['C://test/bye/one.c', 'C://test/bye/two.c']}
You can sort your first list by descending length and then create a copy of your original dictionary, moving each element from the first to the new dict.
In [1]:
llist = ["a", "aa", "ab", "c"]
dict1 = {"xax": 1, "xaax": 2, "xabx": 3, "xabcx": 4}
llist.sort(key=len, reverse=True)
dict2 = dict()
for key in dict1:
success = False
for replace_token in llist:
if replace_token in key:
dict2[replace_token] = dict1.get(key)
success = True
break
if not success:
dict2[key] = dict1.get(key)
print(dict2)
Out [1]:
{'a': 1, 'aa': 2, 'ab': 4}
The general problem is in my code, as well as in your example. It is overwriting all previous values. So I suppose those values shall be in a list:
In [1]:
from typing import List
llist = ["a", "aa", "ab", "c"]
dict1 = {"xax": 1, "xaax": 2, "xabx": 3, "xabcx": 4}
llist.sort(key=len, reverse=True)
dict2 = dict()
for key in dict1:
success = False
for replace_token in llist:
if replace_token in key:
current = dict2.get(replace_token, [])
new = dict1.get(key)
if isinstance(new, List):
current.extend(new)
else:
current.append(new)
dict2[replace_token] = current
success = True
break
if not success:
dict2[key] = dict1.get(key)
print(dict2)
Out [1]:
{'a': [1], 'aa': [2], 'ab': [3, 4]}
You can use re.findall:
import re
lis = ["Hello","Hello1","Test"]
dict1 = {"/****Hello****/": ["C://test/hello/one.c", "C://test/hello/two.c"], "/****Hello1****/": ["C://test/helloNext/one.c", "C://test/helloNext/two.c"], "/****Test****/": ["C://test/bye/one.c", "C://test/bye/two.c"]}
_lis = sorted(lis, key=len, reverse=True)
new_dict = {re.findall('|'.join(_lis), a)[0]:b for a, b in dict1.items()}
Output:
{'Hello': ['C://test/hello/one.c', 'C://test/hello/two.c'], 'Hello1': ['C://test/helloNext/one.c', 'C://test/helloNext/two.c'], 'Test': ['C://test/bye/one.c', 'C://test/bye/two.c']}
import re
lis = ["Hello","Hello1","Test"]
dict1 = {"/****Hello****/": ["C://test/hello/one.c", "C://test/hello/two.c"],
"/****Hello1****/": ["C://test/helloNext/one.c", "C://test/helloNext/two.c"],
"/****Test****/": ["C://test/bye/one.c", "C://test/bye/two.c"]}
dict2 = {}
for x in lis:
print('x:',x)
for y in dict1.copy():
y2 = (y.replace('*', ''))
y2 = (y2.replace('/', ''))
if x == y2:
print(x,y2)
dict2[x] = dict1[y]
print(dict2)
Alternative: no using dict2
if x == y2:
print(x,y2)
dict1[x] = dict1[y]
del dict1[y]
OUTPUT
{'Hello': ['C://test/hello/one.c', 'C://test/hello/two.c'], 'Hello1': ['C://test/helloNext/one.c', 'C://test/helloNext/two.c'], 'Test': ['C://test/bye/one.c', 'C://test/bye/two.c']}
So my input values are as follows:
temp_dict1 = {'A': [1,2,3,4], 'B':[5,5,5], 'C':[6,6,7,8]}
temp_dict2 = {}
val = [5]
The list val may contain more values, but for now, it only contains one. My desired outcome is:
>>>temp_dict2
{'B':[5]}
The final dictionary needs to only have the keys for the lists that contain the item in the list val, and only unique instances of that value in the list. I've tried iterating through the two objects as follows:
for i in temp_dict1:
for j in temp_dict1[i]:
for k in val:
if k in j:
temp_dict2.setdefault(i, []).append(k)
But that just returns an argument of type 'int' is not iterable error message. Any ideas?
Changed your dictionary to cover some more cases:
temp_dict1 = {'A': [1,2,3,4], 'B':[5,5,6], 'C':[6,6,7,8]}
temp_dict2 = {}
val = [5, 6]
for item in val:
for key, val in temp_dict1.items():
if item in val:
temp_dict2.setdefault(key, []).append(item)
print(temp_dict2)
# {'B': [5, 6], 'C': [6]}
Or, the same using list comprehension (looks a bit hard to understand, not recommended).
temp_dict2 = {}
[temp_dict2.setdefault(key, []).append(item) for item in val for key, val in temp_dict1.items() if item in val]
For comparison with #KeyurPotdar's solution, this can also be achieved via collections.defaultdict:
from collections import defaultdict
temp_dict1 = {'A': [1,2,3,4], 'B':[5,5,6], 'C':[6,6,7,8]}
temp_dict2 = defaultdict(list)
val = [5, 6]
for i in val:
for k, v in temp_dict1.items():
if i in v:
temp_dict2[k].append(i)
# defaultdict(list, {'B': [5, 6], 'C': [6]})
You can try this approach:
temp_dict1 = {'A': [1,2,3,4,5,6], 'B':[5,5,5], 'C':[6,6,7,8]}
val = [5,6]
def values(dict_,val_):
default_dict={}
for i in val_:
for k,m in dict_.items():
if i in m:
if k not in default_dict:
default_dict[k]=[i]
else:
default_dict[k].append(i)
return default_dict
print(values(temp_dict1,val))
output:
{'B': [5], 'C': [6], 'A': [5, 6]}
I have a dictionary that consists of numbers and their value
dict = {1:5, 2:5, 3:5}
I have an array with some numbers
arr = [1,2]
What I want to do is:
iterate through the dict and the array
where the dictionary value is equal to the number in the array, set the dictionary value to zero
any value in the dictionary for which there isn't a value in the array matching it, add 1
so in the above example, I should end up with
arr = [1,2]
dict = {1:0, 2:0, 3:6}
The bit I am getting stuck on is creating a variable from the array value and accessing that particular number in the dictionary - using dict[i] for example
arr = [1,2]
data = {1:0, 2:0, 3:6} # don't call it dict because it shadow build-in class
unique = set(arr) # speed up search in case if arr is big
# readable
for k, v in data.items():
if k in unique:
data[k] = 0
else:
data[k] += 1
# oneliner
data = {k: (0 if k in unique else v + 1) for v, k in data.items()}
Additional example:
for a, b, c in [(1,2,3), (4,5,6)]:
print('-',a,b,c)
# will print:
# - 1 2 3
# - 4 5 6
You just need a dict-comprehension that will re-built your dictionary with an if condition for the value part.
my_dict = {1:5, 2:5, 3:5}
arr = [1,2]
my_dict = {k: (0 if k in arr else v+1) for k, v in my_dict.items()}
print(my_dict) # {1: 0, 2: 0, 3: 6}
Note that I have re-named the dictionary from dict to my_dict. That is because by using dict you are overwriting the Python built-in called dict. And you do not want to do that.
Theirs always the dict(map()) approach, which rebuilds a new dictionary with new values to each of the keys:
>>> d = {1:5, 2:5, 3:5}
>>> arr = {1, 2}
>>> dict(map(lambda x: (x[0], 0) if x[0] in arr else (x[0], x[1]+1), d.items()))
{1: 0, 2: 0, 3: 6}
This works because wrapping dict() will automatically convert mapped 2-tuples to a dictionary.
Also you should not use dict as a variable name, since it shadows the builtin dict.
Just use .update method :
dict_1 = {1:5, 2:5, 3:5}
arr = [1,2]
for i in dict_1:
if i in arr:
dict_1.update({i:0})
else:
dict_1.update({i:dict_1.get(i)+1})
print(dict_1)
output:
{1: 0, 2: 0, 3: 6}
P.S : don't use dict as variable
I have a dictionary dict. For each key in dict, there is a list, that has two items in it. One is another dictionary, the other is an integer.
dict = {
'hello' : [
{
'blah' : 1,
'dodo' : 2
},
3
],
'world' : [
{
'foo' : 7,
'bar' : 1
},
8
]
}
I want to sort the dictionary dict on the second item in the list, the integer. And then remove the first 'n' keys from the dictionary. Is there any way to do it? The sorted function works only on lists.
Here is the function I'm trying to do this in.
def create_inverted_index(inverted_index, corpus_tokens, corpus_files):
for file_tokens in corpus_tokens:
file_id = corpus_files[file_tokens[0]]
for token in file_tokens[1]:
if token in inverted_index.keys():
inverted_index[token][1] += 1
if file_id in inverted_index[token][0].keys():
inverted_index[token][0][file_id] += 1
else:
inverted_index[token][0][file_id] = 1
else:
inverted_index[token] = [{file_id : 1}, 1]
You can do it by doing this:
d = {1: [1, 2], 3: [2,4], 4:[3,3], 2:[4,1], 0:[5,0]} # dict to remove items from
sorted_list=sorted(d.items(), key=lambda x: x[1][1])
sorted_keys = [key[1] for key in sorted_list]
n=2 # number of items to remove
for key in sorted_keys[0:n]:
d = dict([(k,v) for k,v in d.items() if v != key ])
This code copies the dict to a list ordered by the second item in dict values. Then it creates a list with only the sorted keys and iterate over it removing them as values from the dictionary.
For my value of d and n=3, output is:
{3: [2, 4], 4: [3, 3]}
For n=2:
{1: [1, 2], 3: [2, 4], 4: [3, 3]}
Ps: Might not be most efficient way of doing this, but does the job
In Python, dictionaries don't have an order. You cannot sort a dict. However, you can take a look at collections.OrderedDict.