Popping the EXACT same value from a dictionary - python

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']}

Related

How to replace items in list with a keys from dictionary in Python

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']

Filter dictionary for values which are not in another dictionary

The two dictionaries mydict1 and mydict2 are given. Key-value-pairs in mydict2 should be removed if the values are already contained in mydict1, regardless of the key and regardless of the order of the values.
The code below delivers the correct output mydict2 = {'key6': [2,1,4], 'key4': [2]}. However, it will be used as part of a larger code. Is there is a better, i.e. more phytonic, way to write it in order to make it more compact and effective without the need of functions?
mydict1 = {'key1':[1],'key2':[1,2],'key3':[1,2,3]}
mydict2 = {'key4':[2],'key5':[2,1],'key6':[2,1,4]}
mydict3 = {}
for md2 in mydict2:
isindict = False
for md1 in mydict1:
isindict = isindict|(sorted(mydict1[md1])==sorted(mydict2[md2]))
if not isindict:
mydict3[md2] = mydict2[md2]
mydict2 = mydict3
The solutions for removing items from a list, comparison of dictionaries and conditional filtering of a dictionary are not transferable in a straightforward way.
Use a list comprehension and dict comprehension to sort all the values of mydict2 then check if the sorted value of mydict1 is in there:
mydict1 = {'key1':[1],'key2':[1,2],'key3':[1,2,3]}
mydict2 = {'key4':[2],'key5':[2,1],'key6':[2,1,4]}
vals = [tuple(sorted(x)) for x in mydict1.values()]
mydict2 = {k:v for (k,v) in mydict2.items() if tuple(sorted(v)) not in vals}
print(mydict2)
Or, in one line:
mydict1 = {'key1':[1],'key2':[1,2],'key3':[1,2,3]}
mydict2 = {'key4':[2],'key5':[2,1],'key6':[2,1,4]}
mydict2 = {k:v for (k,v) in mydict2.items()
if tuple(sorted(v)) not in [tuple(sorted(x)) for x in mydict1.values()]}
print(mydict2)
You can use dict comprehension :
mydict1 = {'key1':[1],'key2':[1,2],'key3':[1,2,3]}
mydict2 = {'key4':[2],'key5':[2,1],'key6':[2,1,4]}
results = {key : value for (key,value) in mydict2.items()
if set(value) not in [ set(val) for val in mydict1.values()]}
print(results)
{'key4': [2], 'key6': [2, 1, 4]}
Edit1
Doesn't work wiht duplicate like this :
mydict1 = {'key1':[1],'key2':[1,2],'key3':[1,2,3], 'key4' : [1, 1, 2]}
mydict2 = {'key4':[2],'key5':[2,1],'key6':[2,1,4], 'key7' : [2, 2, 1]}
Edit 2
Following #Ruzihm awsers and #Peter Wood comments :
mydict3 = {k:v for (k,v) in mydict1.items()
if tuple(sorted(v)) not in set(tuple(sorted(x)) for x in mydict2.values())}
This awser the OP question and avoid creating multiple time the same tuple of value as mentioned by #Peter Wood.
i think this will work:
mydict1 = {'key1':[1],'key2':[1,2],'key3':[1,2,3]}
mydict2 = {'key3':[2],'key5':[2,1],'key6':[2,1,4]}
def merge_two_dicts(x, y):
z = x.copy()
z.update(y)
return z
result = merge_two_dicts(mydict1, mydict2)
print(result)

Find if a List item exists in Dictionary Values and get the Key

I need to find keys from a dictionary that contains values by matching items in a list. My approach is as below...
dict1 = {'a':[1,3,4], "b": [3,4,6], 'c': [88,22,1]}
list1 = [1,3]
links = []
dict2 = {}
for key, value in dict1.iteritems():
for link in list1:
if link in dict1[key]:
links.append(link)
temp = links
dict2[key]=temp
links[:]=[]
print dict2
The output I want is
{'a': [1,3], 'c': 1, 'b': 3}
But with the above code I get...
{'a': [], 'c': [], 'b': []}
Can somebody please explain where I am going wrong. Any help here will be highly appreciated
Here is a simpler implementation:
>>> dict1 = {'a':[1,3,4], "b": [3,4,6], 'c': [88,22,1]}
>>> list1 = [1,3]
>>> res = {}
>>> for k, v in dict1.iteritems():
... if any(i in v for i in list1):
... res[k] = [i for i in v if i in list1]
...
>>> res
{'b': [3], 'c': [1], 'a': [1, 3]}
As for your original solution, it has issues with variable scope and indentation. Here is a solution that will work:
dict1 = {'a':[1,3,4], "b": [3,4,6], 'c': [88,22,1]}
list1 = [1,3]
dict2 = {}
for key, value in dict1.iteritems():
links = []
for link in list1:
if link in dict1[key]:
links.append(link)
dict2[key] = links
print(dict2)
A one-liner:
dict1 = {'a':[1,3,4], "b": [3,4,6], 'c': [88,22,1]}
list1 = [1,3]
res = {key : list(set(value) & set(list1)) for key, value in dict1.items()}
set1=set(list1) can be precomputed for efficiency.

List of Dictionary Manipulation in python

I have a list of the folowing form:
oldlist = [{'x': 1, 'y':2},{'x':2, 'y':2},{'x':1, 'y':3},{'x':1, 'y':2},{'x':3, 'y':4}]
to be converted into
final = [{'x':1,'y':[2,3,2],'count':3},{'x':2,'y':[2],'count':1},{'x':3,'y':[4],'count':1}]
I have tried
oldlist = [{'x': {'a':1,'b':2}, 'y':2},{'x':{'a':6,'b':7}, 'y':2},{'x':{'a':1,'b':2}, 'y':3},{'x':{'a':1,'b':2}, 'y':2},{'x':{'a':10,'b':11}, 'y':4}]
list1=[]
list2=[]
list3=[]
s = set([d['x'] for d in oldlist])
news=list(s)
for item in oldlist:
if item['x'] == news[0]:
list1.append(item['y'])
if item['x'] == news[1]:
list2.append(item['y'])
if item['x'] == news[2]:
list3.append(item['y'])
final=[]
dic1 = {'x':news[0],'y':list1,'count':len(list1)}
dic2 = {'x':news[1],'y':list2,'count':len(list2)}
dic3 = {'x':news[2],'y':list3,'count':len(list3)}
final.append(dic1)
final.append(dic2)
final.append(dic3)
print final
Is there a simpler way to do it? Plus here I knew that x can have only three values so I created three variables list1, list2 and list3. What if x can have several other values and I have to find out a similar list of dictionaries like final! It should also work for strings!
You can collect the dicts to defaultdict where key is x from original dicts and value is list of related y values. Then use list comprehension to generate the final result:
from collections import defaultdict
l = [{'x':1, 'y':2},{'x':2, 'y':2},{'x':1, 'y':3},{'x':1, 'y':2},{'x':3, 'y':4}]
res = defaultdict(list)
for d in l:
res[d['x']].append(d['y'])
final = [{'x': k, 'y': v, 'count': len(v)} for k, v in res.items()] # [{'y': [2, 3, 2], 'x': 1, 'count': 3}, {'y': [2], 'x': 2, 'count': 1}, {'y': [4], 'x': 3, 'count': 1}]
x_list = [item['x'] for item in list1]
set_value = set(x_list)
final_lst = []
for i in set_value:
d = {}
d['x'] = i
d['count'] = x_list.count(i)
d['y'] = []
for item in list1:
if item['x'] == d['x']:
d['y'].append(item['y'])
final_lst.append(d)
print ("Final List", final_lst)
Ok, I used a little trick here to do the job, it's not the most pythonic way but it still gets the answer you want.
The problem was indexing? So a changed s to t, where t is a list and changed the end of the code because you have to put the keys on your dictionaries as strings, so x become 'x' and so on.
See the whole code below:
lista = [{'x':1, 'y':2},{'x':2, 'y':2},{'x':1, 'y':3},{'x':1, 'y':2},{'x':3, 'y':4}]
list1=[]
list2=[]
list3=[]
for d in lista:
print(d)
s = set([d['x'] for d in lista])
t = []
for element in s: #turn t into a list which has the same ordering as s
t.append(element)
for item in lista:
if item['x'] == t[0]:
list1.append(item['y'])
if item['x'] == t[1]:
list2.append(item['y'])
if item['x'] == t[2]:
list3.append(item['y'])
final=[]
dic1 = {'x':t[0],'y':list1,'count':len(list1)}
dic2 = {'x':t[1],'y':list2,'count':len(list2)}
dic3 = {'x':t[2],'y':list3,'count':len(list3)}
final.append(dic1)
final.append(dic2)
final.append(dic3)
print(final)

Acess the dictionary being created inside dictionary comprehension

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]}
>>>

Categories

Resources