so I have the following function:
def check(g,s):
for keys, value in g.items():
for w, val in enumerate(g[keys]):
print(s, g[keys][w], w)
if(s==g[keys][w]):
return 1
else:
return 0
g is a dictionary with an integer as a key and a list as a value
s is an integer I am looking for in the value lists
And I have the following data (a dictionary with an integer as the key and a list as a value):
d={1.4953487812212205: [1, 1.2228445449938519], 2.23606797749979: [2, 1.4953487812212205], 3.309750919646873: [3, 1.8192720851062585]}
The data is actually much longer but I reduced it for our simplicity.
That check function is looking for a specific value in the list of every key in the dictionary and return a 1 or 0. Now the problem is if I take the code and run it as a standalone (fixed dictionary and just run the check function), the code works fine (if I search 3, it will return a 1).
But if I integrate it to my larger code, the w variable never increments and it also only checks the first dictionary entry (only 1 key) instead of all of them and it never finds 3 (since it never gets there).
What can the problem be? I can't seem to put a finger on it.
Don't return 0 until you have checked all the values:
def check(g,s):
for keys, value in g.items():
for w, val in enumerate(g[keys]):
print(s, g[keys][w], w)
if(s==g[keys][w]):
return 1
return 0
Since you are iterating over items(), you don't have to re-lookup the values using the keys:
def check(g,s):
for keys, value in g.items():
for w, val in enumerate(value):
print(s, val, w)
if(s==val):
return 1
return 0
If you use any with a nested generator, you can accomplish the same thing (just look at the dict's values() collection, since you don't seem to care what the key is):
def check(g,s):
if any(s in vlist for vlist in g.values()):
return 1
else:
return 0
And since True = 1 and False = 0, this further reduces to:
def check(g,s):
return any(s in vlist for vlist in g.values())
Related
I have a dictionary in Python:
dict = {("s1", "a1"):1,("s1", "a2"):2,("s3", "a3"):3,("s1", "a3"):1}
Where key is a list(s, a) and value is an integer, so:
dict = {(s, a), i}
I want to pass in a specific s and return a where i is highest.
In the example above, I would expect to recieve "a2" if I passed in "s1".
So far I have the following:
print(max(dict, key=dict.get("s1"))[1])
However this is returning s3. How do I get this to work?
I would filter the dictionary first to only get items with a valid key and then find the key with the maximum value like this:
filtered_dict = {k:v for k, v in d.items() if k[0] == 's1'}
result = max(filtered_dict, key=filtered_dict.get)[1]
print(result)
Output:
a2
The structure of the data is not the ideal one for your given use-case. But if you have no other option, you need to visit every single element in the dict.
You visit each element once:
current_max = -999
result = None
for (k1,k2), value in dict.items():
if k1=="s1" and value > current_max:
result = k2
current_max = value
I have a list of complex dictionaries like this:
data = [
{
"l_1_k": 1,
"l_1_ch": [
{
"l_2_k": 2,
"l_2_ch": [...more levels]
},
{
"l_2_k": 3,
"l_2_ch": [...more levels]
}
]
},
...more items
]
I'm trying to flatten this structure to a list of rows like this:
list = [
{ "l_1_k": 1, "l_2_k": 2, ... },
{ "l_1_k": 1, "l_2_k": 3, ... },
]
I need this list to build a pandas data frame.
So, I'm doing a recursion for each nesting level, and at the last level I'm trying to append to rows list.
def build_dict(d, row_dict, rows):
# d is the data dictionary at each nesting level
# row_dict is the final row dictionary
# rows is the final list of rows
for key, value in d.items():
if not isinstance(value, list):
row_dict[key] = value
else:
for child in value:
build_dict(child, row_dict, rows)
rows.append(row_dict) # <- How to detect the last recursion and call the append
I'm calling this function like this:
rows = []
for row in data:
build_dict(d=row, row_dict={}, rows=rows)
My question is how to detect the last call of this recursive function if I do not know how many nesting levels there are. With the current code, the row is duplicated at each nesting level.
Or, is there a better approach to obtain the final result?
After looking up some ideas, the solution I have in mind is this:
Declare the following function, taken from here:
def find_depth(d):
if isinstance(d, dict):
return 1 + (max(map(find_depth, d.values())) if d else 0)
return 0
In your function, increment every time you go deeper as follows:
def build_dict(d, row_dict, rows, depth=0):
# depth = 1 for the beginning
for key, value in d.items():
if not isinstance(value, list):
row_dict[key] = value
else:
for child in value:
build_dict(child, row_dict, rows, depth + 1)
Finally, test if you reach the maximum depth, if so, at the end of your function you can append it. You will need to add an extra variable which you will call:
def build_dict(d, row_dict, rows, max_depth, depth=0):
# depth = 1 for the beginning
for key, value in d.items():
if not isinstance(value, list):
row_dict[key] = value
else:
for child in value:
build_dict(child, row_dict, rows,max_depth, depth + 1)
if depth == max_depth:
rows.append(row_dict)
Call the function as:
build_dict(d=row, row_dict={}, rows=rows, max_depth=find_depth(data))
Do keep in mind since I don't have a data-set I can use, there might be a syntax error or two in there, but the approach should be fine.
I don't think it is good practice to try to play with mutable default argument in function prototype.
Also, I think that the function in the recursion loop should never be aware of the level it is in. That's the point of the recursion. Instead, you need to think about what the function should return, and when it should exit the recursion loop to climb back to the zeroth level. On the climb back, higher level function calls handle the return value of lower level function calls.
Here is the code that I think will work. I am not sure it is optimal, in term of computing time.
edit: fixed return list of dicts instead of dict only
def build_dict(d):
"""
returns a list when there is no lowerlevel list of dicts.
"""
lst = []
for key, value in d.items():
if not isinstance(value, list):
lst.append([{key: value}])
else:
lst_lower_levels = []
for child in value:
lst_lower_levels.extend(build_dict(child))
new_lst = []
for elm in lst:
for elm_ll in lst_lower_levels:
lst_of_dct = elm + elm_ll
new_lst.append([{k: v for d in lst_of_dct for k, v in d.items()}])
lst = new_lst
return lst
rows = []
for row in data:
rows.extend(build_dict(d=row))
So Im quiet new to python and maybe I´ve searced the wrong words on google...
My current problem:
In python you can return the key to a value when its mentioned in a dictionary.
One thing I wonder, is it possible to return the key if the used value is part of a list of values to the key?
So my testing skript is the following
MainDict={'FAQ':['FAQ','faq','Faq']}
def key_return(X):
for Y, value in MainDict.items():
if X == value:
return Y
return "Key doesnt exist"
print(key_return(['FAQ', 'faq', 'Faq']))
print(key_return('faq'))
So I can just return the Key if I ask for the whole list,
How can I return the key if I just ask for one value of that list as written for the second print? On current code I get the "Key doesnt exist" as an answer.
You can check to see if a value in the dict is a list, and if it is check to see if the value you're searching for is in the list.
MainDict = {'FAQ':['FAQ','faq','Faq']}
def key_return(X):
for key, value in MainDict.items():
if X == value:
return key
if isinstance(value, list) and X in value:
return key
return "Key doesnt exist"
print(key_return(['FAQ', 'faq', 'Faq']))
print(key_return('faq'))
Note: You should also consider making MainDict a parameter that you pass to key_return instead of a global variable.
You can do this using next and a simple comprehension:
next(k for k, v in MainDict.items() if x == v or x in v)
So your code would look like:
MainDict = {'FAQ':['FAQ','faq','Faq']}
def key_return(x):
return next(k for k, v in MainDict.items() if x == v or x in v)
print(key_return(['FAQ', 'faq', 'Faq']))
#FAQ
print(key_return('faq'))
#FAQ
You can create a dict that maps from values in the lists to keys in MainDict:
MainDict={'FAQ':['FAQ','faq','Faq']}
back_dict = {value: k for k,values in MainDict.items() for value in values}
Then rewrite key_return to use this dict:
def key_return(X):
return back_dict[X]
print(key_return('faq'))
The line back_dict = {value: k for k,values in MainDict.items() for value in values} is a dictionary comprehension expression, which is equivalent to:
back_dict = {}
for k,values in MainDict.items():
for value in values:
back_dict[value] = k
This approach is more time-efficient that looping over every item of MainDict every time you search, since it only requires a single loopkup rather than a loop.
Is there a shorter way to initialize this loop?
It feels like typing "val" four times for such a simple statement might not be the fastest way to do it.
(The example is a random code for explaining my point, the actual loop content would be much more complex.)
values=[4,8,0,1,5,8,3]
for val in [val for val in values if val!=1]:
print(val)
Generator expression (no need to create yet another list to iterate over) and the filter() function (creates an iterator) come to mind:
values = [4,8,0,1,5,8,3]
# generator expression instead of list expressen - is more efficient
for val in (val for val in values if val != 1):
print(val)
# filter the list - creates an iterator
for val in filter(lambda x:x != 1, values):
print (val)
Output:
4
8
0
5
8
3
Write a function named "indexed_kvs" that doesn't take any parameters and returns a new key-value store containing the integers from 0 to 36 as values each stored at a key which is a string containing the digits of the integer. For example the key-value "0":0 will be in your returned key-value store (include both 0 and 36 in your list). (My code below)
def indexed_kvs():
d = dict()
for x in range(37):
d[x] = x
return d
I keep on getting the first key and value; how do I get all the keys and values?
You return from inside the loop which is a common mistake that can be avoided altogether by using a dict comprehension, at least in this simple case:
def indexed_kvs():
return {str(x): x for x in range(37)}
As #Loocid comment, the return statement shouldn't be inside the for loop, so the correct code would be:
def indexed_kvs():
d = dict()
for x in range(37):
d[str(x)] = x
return d
You have your "return d", inside you loop. So, what happens is that -
1) The function begins
2) The for loop executes once:
a) adds 0 to the dictionary at key 0,
b) encounters return d, them thinks- 'Okay! I got a return statement. I gotta exit! '
c) And Boom! Your function is done with
So, just move your return d out of you for loop. So, the exiting of the function will take place when, the loop is over.
So your new code should be:
def indexed_kvs():
d = dict()
for x in range(37):
d[str(x)] = x
return d