iterate over a subset of dictionary keys - python

I am looking to learn how to pass certain keys/values in a dictionary to another function within a for loop. The "certain" keys all share the same initial string and are incremented by a trailing integer like this:
data = {}
data["HMD1"] = [a,b,c]
data["HMD2"] = [d,f,g] #and so on...
There are other keys with dissimilar names witin the same dictionary. Now within a for loop I would like to pass the values for each key that starts with "HMD" to another function. Here is a minimal working example of a failed attempt:
data = {}
data["HMD1"] = [0,2,3]
data["HMD2"] = [5,6,4]
data["not"] = 1237659398
data["HMD3"] = [1,1,1]
def dummyfun(vargin):
print(vargin)
return vargin
for f in range(1,2,1):
out = dummyfun(data[eval(''.join(("HMD",str(f))))])
This was a poor guess, of course it returns an error because eval() tries to evaluate "HMD1" which is not a variable but a key in data. Does anyone know how to do this properly?

You don't need eval at all for this. You only need to build the string with .format for example
for f in range(1,4): #range don't include the end point
out = dummyfun(data["HMD{}".format(f)])
with this you get the desire result. But that will fail if the key is not in the dict, you can check it first, catch the exception or provide a default value in case the desire key is not there
#check first
for f in range(1,4):
key = "HMD{}".format(f)
if key in data:
out = dummyfun(data[key])
#catch the exception
for f in range(1,4):
try:
out = dummyfun(data["HMD{}".format(f)])
except KeyError:
print("key",f,"is not in the data")
#provide a default value
for f in range(1,4):
out = dummyfun(data.get("HMD{}".format(f),None))

Just iterate through the dictionary using a for loop and use an if statement to check for validity of the keys:
for key in yourDict: #a for loop for dict iterates through its keys
if 'HMD' in key: #or you can replace with any other conditional
#DO WHAT YOU WANT TO DO HERE
And here's a quick working example:
>>> data = {'HMD1': [1,2,3], 'HMD23':'heyo mayo', 'HMNOT2':'if this prints, I did something wrong'}
>>> for key in data:
... if 'HMD' in key:
... print data[key]
...
[1, 2, 3]
heyo mayo
With further understand of what you want, you can also look at this backwards and create key strings and print the values that those key's point to:
#let's say you want to print HMD1, HMD2, HMD4, but not anything else
keylist = [#list of keys that you want]
for key in keylist:
if key in data:
print data[key]
and, again, a working example.
>>> data = {'HMD1': [1,2,3], 'HMD3':'heyo mayo, this shouldnt print', 'HMD4':123, 'HMD2':['g', 'h', 'i'], 'HMNOT2':'if this prints, I did something wrong'}
>>> keylist = ['HMD1', 'HMD2', 'HMD4']
>>> for key in keylist:
... if key in data:
... print data[key]
...
[1, 2, 3]
['g', 'h', 'i']
123

Related

Comparing element inside value of a key in a dictionary is equal to the next key

d = {
0:{1,2,3},
1:{567},
2:{2,3,5,8},
3:{4,5,7,9},
4:{6,7,8}
}
I would like to compare the value of the first k-v pair with the key of the next k-v pair.
Example:
To check if 1 exists in {1,2,3} or 2 exists in {567}
If it does exist then I would like to delete the k that exists in the value.
Output should look like:
d = {
0:{1,2,3},
2:{2,3,5,8}
}
I have tried using dictionary iterators with various permutations and combinations, but with no result. What would be the best way to achieve the result?
Python dictionary are not ordered, so I'm not sure you can really speak of "next" of "previous" here. Using a pandas Series would be more appropriate.
However, you can still iterate over the keys and define this as your order.
previous = {}
dict_items = list(d.items())
for k,v in dict_items:
if k in previous:
del d[k]
previous = v
EDIT: to make sure the keys are in the correct order, changing dict_items with:
dict_items = sorted(d.items(),key=lambda x:x[0])
would do it
Guessing by your example and requirement, you're on Python 3.6+, where dicts keep insertion orders. You can do:
In [57]: d = {
...: 0:{1,2,3},
...: 1:{567},
...: 2:{2,3,5,8},
...: 3:{4,5,7,9},
...: 4:{6,7,8}
...: }
# Get an iterator from dict.keys
In [58]: keys_iter = iter(d.keys())
# Get the first key
In [59]: first_key = next(keys_iter)
# Populate output dict with first key-value
In [60]: out = {first_key: d[first_key]}
# Populate out dict with key-values based on condition by
# looping over the `zip`-ed key iterator and dict values
In [61]: out.update({k: d[k] for k, v in zip(keys_iter, d.values())
if k not in v})
In [62]: out
Out[62]: {0: {1, 2, 3}, 2: {2, 3, 5, 8}}
It took me awhile to figure out what you wanted. Below, I have re-worded your example:
EXAMPLE:
Suppose the input dictionary is as follows:
0:{1,2,3},
1:{567},
2:{2,3,5,8},
3:{4,5,7,9},
4:{6,7,8}
We have...
key of 0:{1,2,3} is 0
value of 0:{1,2,3} is {1,2,3}
key of 2:{2,3,5,8} is 2
value of 2:{2,3,5,8} is {2,3,5,8}
We execute code similar to the following:
if key of 1:{567} in value of 0:{1,2,3}:
# if 1 in {1,2,3}:
delete 1:{567}
if key of 2:{2,3,5,8} in value of 1:{567}:
# if 2 in {567}:
delete 2:{2,3,5,8}
and so on...
"""
The following code should accomplish your goal:
def cleanup_dict(in_dict):
# sort the dictionary keys
keys = sorted(indict.keys())
# keys_to_delete will tell us whether to delete
# an entry or not
keys_to_delete = list()
try:
while True:
prv_key = next(keys)
nxt_key = next(keys)
prv_val = in_dict[prv_key]
if (nxt_key in prv_val):
keys_to_delete.append(nxt_key)
except StopIteration:
pass
for key in keys_to_delete:
del in_dict[key]
return

Convert String to multi-level dictionary keys?

I am giving the user the ability to check a specific key in a multi-level dictionary. My idea is that they will pass the path to the key like this:
root.subelement1.subelement2.key
This can be of arbitrary length and depth.
Once I have the string (above) from the user, I'll split it and get a list of each individual component:
elements = ['root', 'subelement1', 'subelement2', 'key']
All of this I can do. The next part is where I am stuck. How can I query the dictionary key, specified by the above when it's arbitrary length?
My initial thought was to do something like my_dict[elements[0]][elements[1]]...but that doesn't scale or work when my user doesn't pass exactly the length I expect.
How can I get the data at an arbitrary key depth, in this case?
A couple examples:
User passes country.US.NewYork => I query `my_dict['country']['US']['NewYork']
User passes department.accounting => I query my_dict['department']['accounting']
User passes id => I query my_dict['id']
User passes district.District15.HenryBristow.principal => I query my_dict['district']['District15']['HenryBristow']['principal']
you could do that using reduce which will query the keys in the nested dictionaries:
q = "district.District15.HenryBristow.principal"
my_dict = {"district" : {"District15" : {"HenryBristow" : {"principal" : 12}}}}
from functools import reduce # python 3 only
print(reduce(lambda x,y : x[y],q.split("."),my_dict))
result:
12
If you want to avoid to catch KeyError in case the data doesn't exist with this path, you could use get with a default value as empty dictionary:
reduce(lambda x,y : x.get(y,{}),q.split("."),my_dict)
Trying to get an unknown value returns an empty dictionary. The only drawback is that you don't know from where exactly the path got lost, so maybe leaving the KeyError be raised wouldn't be so bad:
try:
v = reduce(lambda x,y : x[y],q.split("."),my_dict)
except KeyError as e:
print("Missing key: {} in path {}".format(e,q))
v = None
Use recursion. Ex:
root = {
'subelement1': {
'subelement2': {
'key': 'value'
}
}
}
elements = ['subelement1', 'subelement2', 'key']
def getElem(d, keys):
if keys == []:
return None
else:
key = keys[0]
remainingKeys = keys[1:]
if remainingKeys == []:
return d[key]
else:
if type(d[key]) == dict:
return getElem(d[key], remainingKeys)
else:
return None
print(getElem(root, elements))
from a python 2.x perspective, you can do this with reduce.
query_list = keys.split(":")
print reduce(lambda x,y: x[y], [my_dict] + query_list)
But in general, you'll want to do this with a recursive or iterative function if you want to do error handling beyond throwing a KeyError.
You can transverse the dictionary using a for loop:
s = 'root.subelement1.subelement2.key'
d1 = {'root':{'subelement1':{'subelement2':{'key':15, 'key1':18}}}}
new_d = d1
for key in s.split('.'):
new_d = new_d[key]
print(new_d)
Output:
15
u can do this like below
my_dict = someDict
tmpDict = dict(someDict) # a coppy of dict
input = "x.u.z"
array = input.split(".")
for key in array:
tmpDict = tmpDict[key]
print(tmpDict)
but your question is very challenging:
u say if user send country.us then go to my-dict.country.us
but what happen if one of this path in my_dict be a list code will results error
u can handle this by check type
if isinstance(tmpDict , dict ):
tmpDict = tmpDict[key]
else:
# u should say what u want else (a Recursive method u will need)
edit
if user address maybe wrong you should check my_dict have this field or not sample code is below but will be many if i don't like that!
if key not in tmpDict:
print("Bad Path")
return

Reset List When Condition Met

I'm trying to make a function that reads through a protocol buffer and creates a dictionary with a list matched up to each key, like so:
Source:
{
name: "foo"
...
some_value: "a"
some_value: "b"
},
{
name: "bar"
...
some_value: "c"
some_value: "d"
}
Desired Output:
{'foo': ['a','b'], 'bar': ['c','d',]}
Here is my code:
import re
STATIC_SRC = '/path/to/my/file.txt'
def CountBrackets(line):
if '{' in line:
return 1
if '}' in line:
return -1
else:
return 0
with open(STATIC_SRC, 'r') as src_file:
bracket_count = 0
key = ''
values = []
my_dict = {}
for line in src_file:
line = line.strip()
bracket_count += CountBrackets(line)
# Finds line like 'name: "foo"' and stores 'foo' as key
if line.startswith('name:'):
key = re.findall('"([^"]*)"', line)
key = ''.join(key)
# Finds line like 'some_value: "a"' and adds 'a' to list
if line.startswith('some_value:'):
value = re.findall('"([^"]*)"', line)
values.append(value)
# When bracket count returns to 0, it's reached the end of a tupe
# and should store the current key and list.
if bracket_count == 0:
my_dict[key] = values
del values[:] # This is where I'm having issues.
print(role_dict)
My problem is that I can't get the list to successfully clear at the end of the tuple (in the source file). I have tried the following two methods, neither gave the correct output.
Method:
values = []
Result:
{'foo': ['a', 'b'], 'bar': ['a','b','c','d']}
Method:
del values[:]
Result:
{'foo': [], 'bar': []}
I've had it print all the keys/values as it loops and those are working as desired. It's also writing to the dictionary at the write time based on bracket count. It seems that the method I used for clearing somehow clears 'values' even after they've been added to the dictionary.
Can anyone shed some light on what's going wrong here and how to properly empty the list of values? Thanks!
EDIT: By request, tl;dr
I'd like the program to loop through this logic:
if x:
- store something to 'key'
if y:
- add something to a list 'values'
if z:
- write the current 'key' and 'values' to a dictionary
- clear the list 'values'
How do I clear the list of values at the end?
I don't know why you are getting that output on your first attempt. It worked for me. See below.
with open(STATIC_SRC, 'r') as src_file:
bracket_count = 0
key = ''
values = []
my_dict = {}
for line in src_file:
print(values)
line = line.strip()
bracket_count += CountBrackets(line)
# Finds line like 'name: "foo"' and stores 'foo' as key
if line.startswith('name:'):
key = re.findall('"([^"]*)"', line)
key = ''.join(key)
# Finds line like 'some_value: "a"' and adds 'a' to list
if line.startswith('some_value:'):
value = re.findall('"([^"]*)"', line)
values.extend(value) # append create a new list inside the existing list
# When bracket count returns to 0, it's reached the end of a tupe
# and should store the current key and list.
if bracket_count == 0:
my_dict[key] = values
values = []
print(my_dict) # the name of the dict was wrong
The result is
{'foo': ['a', 'b'], 'bar': ['c', 'd']}
I just edited the last print and replaced append with extend.
You cannot del values because that will delete the value in the dict, as it is the same object in memory.
d = {}
k = [1,2,3]
d['a'] = k
d
# {'a': [1, 2, 3]}
id(d['a']) == id(k)
# True
Running Python 2.7.6.

Replace dict key by value of other dict

Today I need to replace the key of dict one by value of dict two. Dict one has multiple keys and I only want to replace the keys which match dict 2.
In the end I want to get the dict one back with the old keys (the ones which did not match) and the new keys (which have been changed when they matched)
I wrote the following script but I get no output so I am not sure if I am doing it right, can someone explain to me?
Thanks a lot
ERCC = {}
my_file = open('a.txt')
for line in my_file:
config,name = line.strip().split()
ERCC[contig] = name
RSEM = {}
names_file = open('b.txt')
for line in names_file:
genes, count = line.strip().split()
RSEM[gene] = count
def convert(RSEM,ERCC):
for key, value in RSEM.items():
for keys, values in ERCC.items():
if keys == key:
RSEM[key] = values
return RSEM
print RSEM
convert(RSEM, ERCC)
>>> dic={}
>>> for k,v in myboi.items():
r=input("Enter item to Update write in ""=")
if r:
dic[r]=v
else:
dic[k]=v
Enter item to Update write in ="Mahesh"
Enter item to Update write in ="Saka"
>>>
>>> dic
{'Mahesh': 'Mahesh', 'Saka': 'Mahesh'}
You want compulsary input key in this program you want update one or more time you empty dic={}
result={'Mahesh': 'Mahesh', 'Saka': 'Mahesh'}
>>> fi.close()
>>> fi=open("m.txt","r")
>>> fi.readlines()
['Maheshname']
>>> fi=open("m.txt","w+")
>>> for k,v in myboi.items():
fi.write("'"+k+"'"+":"+"'"+v+"'")
>>> fi.close()
>>> fi=open("m.txt","r")
>>> fi.readlines()
["'Mahesh':'Mahesh''name':'Mahesh'"]
Here's a two-liner for the convert function:
RSEM = {key: ERCC.get(key, RSEM[key]) for key in RSEM}
print RSEM
To dump a dict to a file just do:
with open("your_file_name", "w") as dumpfile:
dumpfile.write(str(RSEM))
Your code seems to be fine. But you have used return statement before print statement. The execution of convert function stops at return *** and the print statement is not executed at all. That is the reason why you are not getting any output.

Defining a list of values for a dictionary key using an external file

I have a file with a list of paired entries (keys) that goes like this:
6416 2318
84665 88
90 2339
2624 5371
6118 6774
And I've got another file with the values to those keys:
266743 Q8IUM7
64343 H7BXU6
64343 Q9H6S1
64343 C9JB40
23301 Q8NDI1
23301 A8K930
As you can see the same key can have more than one value. What I'm trying to do is creating a dictionary by automatically creating the initial k, v pair, and then append more values for each entry that is already in the dictionary, like this:
Program finds "266743: 'Q8IUM7'", then "64343: 'H7BXU6'". And when it finds "64343: 'Q9H6S1'" it does this: "64343: ['H7BXU6', 'Q9H6S1']".
This is what I have so far:
# Create dictionary
data = {}
for line in inmap:
value = []
k, v = [x.strip() for x in line.split('\t')]
data[k] = value.append(v)
if k in data.viewkeys() == True and v in data.viewvalues() == False:
data[k] = value.append(v)
But the if statement seems to not be working. That or having the value = [] inside the for loop. Any thoughts?
This is not a good idea. You should be using a list from the start and expand that list as you go along, not change from "string" to "list of strings" when more than one value is found for the key.
For this, you can simply use
from collections import defaultdict
data = defaultdict(list)
for line in inmap:
k, v = (x.strip() for x in line.split('\t'))
data[k].append(v)
This works because a defaultdict of type list will automatically create a key together with an empty list as its value when you try to reference a key that doesn't yet exist. Otherwise, it behaves just like a normal dictionary.
Result:
>>> data
defaultdict(<type 'list'>, {'23301': ['Q8NDI1', 'A8K930'],
'64343': ['H7BXU6', 'Q9H6S1', 'C9JB40'], '266743': ['Q8IUM7']})

Categories