Avoid emptying dictionary recursively - python

I am trying to create a dictionary from a list recursively and my code only works when there is only one item in the list. It fails for multiple items and I suspect that this is because the dictionary is being recreated through each instance of the recursion instead of adding to it after the first instance. How can I avoid doing this so that the whole list is converted to a dictionary?
Note: the list is a list of tuples containing two items.
def poncePlanner(restaurantChoices):
if len(restaurantChoices) == 0:
return {}
else:
name, resto = restaurantChoices[0][0], restaurantChoices[0][1]
try:
dic[name] = resto
poncePlanner(restaurantChoices[1:])
return dic
except:
dic = {name: resto}
poncePlanner(restaurantChoices[1:])
return dic
Intended input and output:
>>> restaurantChoice = [("Paige", "Dancing Goats"), ("Fareeda", "Botiwala"),
("Ramya", "Minero"), ("Jane", "Pancake Social")]
>>> poncePlanner(restaurantChoice)
{'Jane': 'Pancake Social',
'Ramya': 'Minero',
'Fareeda': 'Botiwala',
'Paige': 'Dancing Goats'}

You have the edge condition, so you need to define what to do when you have more than one. Here you just take the first tuple, make a dict, and then add the results of recursion into that dict:
restaurantChoice = [("Paige", "Dancing Goats"), ("Fareeda", "Botiwala"),
("Ramya", "Minero"), ("Jane", "Pancake Social")]
def poncePlanner(restaurantChoice):
if not restaurantChoice:
return {}
head, *rest = restaurantChoice
return {head[0]: head[1], **poncePlanner(rest)}
poncePlanner(restaurantChoice)
Returning:
{'Jane': 'Pancake Social',
'Ramya': 'Minero',
'Fareeda': 'Botiwala',
'Paige': 'Dancing Goats'}

Since restaurantChoices are already (key,value) pairs, you can simply use the built-in function dict to create the dictionary:
def poncePlanner(restaurantChoices):
return dict(restaurantChoices)
Without built-in functions, you can also use a simple for-loop to return the desired transformation:
def poncePlanner(restaurantChoices):
result = {}
for key,value in restaurantChoices:
result[key] = value
return result
If you really want recursion, I would do something like this, but it doesn't make sense because the lists are not nested:
def poncePlanner(restaurantChoices):
def recursion(i, result):
if i<len(restaurantChoices):
key, value = restaurantChoices[i]
result[key] = value
recursion(i+1, result)
return result
return recursion(0,{})
This recursive function has O(1) time/space complexity per call, so it runs with optimal efficiency.
The main problem with the original code is that the dictionary dic is not passed to the deeper recursion calls, so the new contents are never added to the final dictionary. (They contents added to new dictionaries and forgotten).

Related

How to return all paths from a dictionary?

Lets say i have this dictionary
obj = {'layerA1':'string','layerA2':{'layerB1':{'layerC1':{},'layerC2':{}},
'layerB2':{}}}
i would need to return
['layerA2','layberB1','layerC1']
['layerA2','layerB1','layerC2']
['layerA2','layerB2']
It should work regardless of how deep the dictionary gets.
Currently trying with some recursive functions but i can't seem to get it right.
What i currently have is this:
obj = {'layerA1':'string','layerA2':{'layerB1':{'layerC1':{},'layerC2':{}},
'layerB2':{}}}
hierarchy_list = []
def find_hierachy(param):
some_list = []
for key, value in param.items():
if type(param[key]) is dict:
some_list.append(key)
hierarchy_list.append(some_list)
find_hierachy(param[key])
find_hierachy(obj)
print(hierarchy_list)
[['layerA2'], ['layerB1', 'layerB2'], ['layerC1', 'layerC2'], ['layerC1', 'layerC2'], ['layerB1', 'layerB2']]
I don't know how to get it to return each hierarchical path made of keys
As you noticed in your code, you need to keep track of the path you have taken sofar, this is often referred to as the prefix. By storing the prefix and passing it along, we can keep track of the previous keys. An important thing to keep in mind is that default variables in python should be immutable (tuples) unless you know what happens with mutable objects while using recursion.
answer = []
def hierarchy(dictionary, prefix=()):
for key, value in dictionary.items():
if isinstance(value, dict) and value:
hierarchy(value, (*prefix, key))
else:
answer.append((*prefix, key))
If you want the final answer to be a list, you can loop over the answers and cast them to a list, or send the list as prefix. This requires us to copy the list to the next level of the hierarchy. Which is done using [*prefix, key] which makes a new copy of the list.
obj = {'layerA1': 'string', 'layerA2': {'layerB1': {'layerC1': {}, 'layerC2': {}},
'layerB2': {}}}
if __name__ == '__main__':
answer = []
def hierarchy(dictionary, prefix=None):
prefix = prefix if prefix is not None else []
for key, value in dictionary.items():
if isinstance(value, dict) and value:
hierarchy(value, [*prefix, key])
else:
answer.append([*prefix, key])
hierarchy(obj)
print(answer)
Output
[['layerA1'], ['layerA2', 'layerB1', 'layerC1'], ['layerA2', 'layerB1', 'layerC2'], ['layerA2', 'layerB2']]
Note:
Type checking can be done using isinstance(obj, type), which is the preferred way above type(obj) is type.

Create a dictionary with specific pairs from other dictionaries

This list:
data=[[{'t1':'text1.txt','date1':'class1'}],[{'t2':'text2.txt','date2':'class2'}]]
data
gives
[[{'t1': 'text1.txt', 'date1': 'class1'}],
[{'t2': 'text2.txt', 'date2': 'class2'}]]
and I want to turn it into this:
EDIT brackets added
[[{'text1.txt': 'class1'}], [{'text2.txt': 'class2'}]]
which means:
to create a list where each sublist inside, will be comprised of a dictionary where the key would be the value of the first dictionary in the first sublist and the value would be the value of the second dictionary of the first sublist and so on for the following sublists.
My attempt was this:
se=[]
for i in data:
for j in i:
jk=j.values()
se.append(jk)
se
Iterate through each dictionary in nested list and create a tuple from values() method for each dictionary like this tuple(dict.values()). After converting to tuple you can use dict() to create dictionary from the tuple like this dict([tuple(dict.values())])
Note: If your dictionary has exactly two keys then only it will work.
res = [[dict([tuple(d.values())]) for d in lst]for lst in data]
print(res)
Output:
[[{'text1.txt': 'class1'}], [{'text2.txt': 'class2'}]]
Your code does most of the job. You can add another line to get the desired results:
In [108]: se
Out[108]: [dict_values(['text1.txt', 'class1']), dict_values(['text2.txt', 'class2'])]
In [109]: [[{list(x)[0]:list(x)[1]} for x in se]]
Out[109]: [[{'text1.txt': 'class1'}, {'text2.txt': 'class2'}]]
Try this:
data=[[{'t1':'text1.txt','date1':'class1'}],[{'t2':'text2.txt','date2':'class2'}]]
all_vals = [];
for i in data:
for j in i:
for key in j:
all_vals.append(j[key])
new_list = [];
for i in range(0,len(all_vals)-1):
if (i % 2) == 0:
new_dict = {};
new_dict = {all_vals[i]:all_vals[i+1]}
new_list.append(new_dict)
else:
continue
print(new_list)
Output:
[{'text1.txt': 'class1'}, {'text2.txt': 'class2'}]
This code works regardless of the length of your list.
The following function should convert the inputs to the outputs you requested.
def convert_to_list_of_list_of_dictionaries(input_dictionaries):
ret_dictionaries = []
for inp in input_dictionaries:
k, v = inp[0].values()
ret_dictionaries.append({k, v})
return ret_dictionaries
However, there are a few things going on with the input/outputs that are little concerning and make the data harder to work with.
On the input side, the data is being wrapped in an extra list that in this context, does not provide any function, and forces you to index the first element of the inner list to access the dict k, v = inp[0].values(). On the output side, we're doing the same thing, which makes it harder to iterate over the outputs. It would look something like:
# psuedocode
for kv in reformatted_outputs:
unwrapped_dict = kv[0]
key, value = next(iter(unwrapped_dict.items()))
# process key and value
instead, if you had an output format like ``{'text1.txt': 'class1', 'text2.txt': 'class2'}`, you could process data like:
key, value in reformatted_outputs.items():
# process key and value
If you have the ability to modify the inputs and outputs of what you're working on, this could save you some trouble, and anyone you're working with some head scratches.
If you wanted to modify the output format, your function could look something like:
def convert_to_single_dictionary(input_dictionaries):
ret = {}
for inp in input_dictionaries:
print(inp)
# it looks like the input data is being wrapped in an extra list
k, v = inp[0].values()
ret[k] = v
return ret
Hope this is helpful and thanks for asking the question!

Compare list with dictionary (that contains wildcards), return values

I have a list that contains several strings and a dictionary with strings (that contain wildcards) as keys and integers as values.
For example like this:
list1 = ['i', 'like', 'tomatoes']
dict1 = {'tomato*':'3', 'shirt*':'7', 'snowboard*':'1'}
I would like to go through list1 and see if there is a key in dict1 that (with the wildcard) matches the string from list1 and get the respective value from dict1. So in this case 3 for 'tomato*'.
Is there a way to iterate over list1, see if one of the dict1 keys (with wildcards) matches with this particular string and return the value from dict1?
I know I could iterate over dict1 and compare the keys with the elements in list1 this way. But in my case, the dict is very large and in addition, I have a lot of lists to go through. So it would take too much time to loop through the dictionary every time.
I thought about turning the keys into a list as well and get wildcard matches with a list comprehension and fnmatch(), but the returned match wouldn't be able to find the value in the dict (because of the wildcard).
Here is a data structure implemented using default python package to help you.
from collections import defaultdict
class Trie(defaultdict):
def __init__(self, value=None):
super().__init__(lambda: Trie(value)) # Trie is essentially hash-table within hash-table
self.__value = value
def __getitem__(self, key):
node = self
if len(key) > 1: # allows you to access the trie like this trie["abc"] instead of trie["a"]["b"]["c"]
for char in key:
node = node[char]
return node
else: # actual getitem routine
return defaultdict.__getitem__(self, key)
def __setitem__(self, key, value):
node = self
if len(key) > 1: # allows you to access the trie like this trie["abc"] instead of trie["a"]["b"]["c"]
for char in key[:-1]:
node = node[char]
node[key[-1]] = value
else: # actual setitem routine
if type(value) is int:
value = Trie(int(value))
defaultdict.__setitem__(self, key, value)
def __str__(self):
return str(self.__value)
d = Trie()
d["ab"] = 3
print(d["abcde"])
3

Dict comprehension, tuples and lazy evaluation

I am trying to see if I can pull off something quite lazy in Python.
I have a dict comprehension, where the value is a tuple. I want to be able to create the second entry of the tuple by using the first entry of the tuple.
An example should help.
dictA = {'a': 1, 'b': 3, 'c': 42}
{key: (a = someComplexFunction(value), moreComplexFunction(a)) for key, value in dictA.items()}
Is it possible that the moreComplexFunction uses the calculation in the first entry of the tuple?
You could add a second loop over a one-element tuple:
{key: (a, moreComplexFuntion(a)) for key, value in dictA.items()
for a in (someComplexFunction(value),)}
This gives you access to the output of someComplexFunction(value) in the value expression, but that's rather ugly.
Personally, I'd move to a regular loop in such cases:
dictB = {}
for key, value in dictA.items():
a = someComplexFunction(value)
dictB[key] = (a, moreComplexFunction(a))
and be done with it.
or, you could just write a function to return the tuple:
def kv_tuple(a):
tmp = someComplexFunction(a)
return (a, moreComplexFunction(tmp))
{key:kv_tuple(value) for key, value in dictA.items()}
this also gives you the option to use things like namedtuple to get names for the tuple items, etc. I don't know how much faster/slower this would be though... the regular loop is likely to be faster (fewer function calls)...
Alongside Martijn's answer, using a generator expression and a dict comprehension is also quite semantic and lazy:
dictA = { ... } # Your original dict
partially_computed = ((key, someComplexFunction(value))
for key, value in dictA.items())
dictB = {key: (a, moreComplexFunction(a)) for key, a in partially_computed}

python: how to get a subset of dict

I have a dict that has many elements, I want to write a function that can return the elements in the given index range(treat dict as array):
get_range(dict, begin, end):
return {a new dict for all the indexes between begin and end}
How that can be done?
EDIT: I am not asking using key filter... eg)
{"a":"b", "c":"d", "e":"f"}
get_range(dict, 0, 1) returns {"a":"b", "c":"d"} (the first 2 elements)
I don't care the sorting...
Actually I am implementing the server side paging...
Edit: A dictionary is not ordered. It is impossible to make get_range return the same slice whenever you have modified the dictionary. If you need deterministic result, replace your dict with a collections.OrderedDict.
Anyway, you could get a slice using itertools.islice:
import itertools
def get_range(dictionary, begin, end):
return dict(itertools.islice(dictionary.iteritems(), begin, end+1))
The previous answer that filters by key is kept below:
With #Douglas' algorithm, we could simplify it by using a generator expression:
def get_range(dictionary, begin, end):
return dict((k, v) for k, v in dictionary.iteritems() if begin <= k <= end)
BTW, don't use dict as the variable name, as you can see here dict is a constructor of dictionary.
If you are using Python 3.x, you could use dictionary comprehension directly.
def get_range(dictionary, begin, end):
return {k: v for k, v in dictionary.items() if begin <= k <= end}
Straight forward implementation:
def get_range(d, begin, end):
result = {}
for (key,value) in d.iteritems():
if key >= begin and key <= end:
result[key] = value
return result
One line:
def get_range2(d, begin, end):
return dict([ (k,v) for (k,v) in d.iteritems() if k >= begin and k <= end ])
resting assured that what you really want an OrderedDict, you can also use enumerate:
#!/usr/bin/env python
def get_range(d, begin, end):
return dict(e for i, e in enumerate(d.items()) if begin <= i <= end)
if __name__ == '__main__':
print get_range({"a":"b", "c":"d", "e":"f"}, 0, 1)
output:
{'a': 'b', 'c': 'd'}
ps: I let you use 0, 1 as range values, but you should use 0, 2 to sign the "first two elements" (and use begin <= i < end as comparison function
As others have mentioned, in Python dictionaries are inherently unordered. However at any given moment a list of their current keys or key,value pairs can be obtained by using their keys()or items() methods.
A potential problem with using these lists is that not only their contents, but also the order it is returned in will likely vary if the dictionary has been modified (or mutated) since the last time they were used. This means you generally can't store and reuse the list unless you update it every time the dictionary is is changed just in case you're going to need it.
To make this approach more manageable you can combining a dictionary and the auxiliary list into a new derived class which takes care of the synchronization between the two and also provides a get_range() method that make use of the list's current contents. Below is sample code showing how this could be done. It's based on ideas I got from the code in this ActiveState Python Recipe.
class dict_with_get_range(dict):
def __init__(self, *args, **kwrds):
dict.__init__(self, *args, **kwrds)
self._list_ok = False
def _rebuild_list(self):
self._list = []
for k,v in self.iteritems():
self._list.append((k,v))
self._list_ok = True
def get_range(self, begin, end):
if not self._list_ok:
self._rebuild_list()
return dict(self._list[i] for i in range(begin,end+1))
def _wrapMutatorMethod(methodname):
_method = getattr(dict, methodname)
def wrapper(self, *args, **kwrds):
# Reset 'list OK' flag, then delegate to the real mutator method
self._list_ok = False
return _method(self, *args, **kwrds)
setattr(dict_with_get_range, methodname, wrapper)
for methodname in 'delitem setitem'.split():
_wrapMutatorMethod('__%s__' % methodname)
for methodname in 'clear update setdefault pop popitem'.split():
_wrapMutatorMethod(methodname)
del _wrapMutatorMethod # no longer needed
dct = dict_with_get_range({"a":"b", "c":"d", "e":"f"})
print dct.get_range(0, 1)
# {'a': 'b', 'c': 'd'}
del dct["c"]
print dct.get_range(0, 1)
# {'a': 'b', 'e': 'f'}
The basic idea is to derive a new class from dict that also has an internal contents list for use by the new get_range() method it provides that regular dictionary objects don't. To minmize the need to update (or even create) this internal list, it also has a flag indicating whether or not the list is up-to-date, and only checks it and rebuilds the list when necessary.
To maintain the flag, each inherited dictionary method which potentially changes (or mutates) the dictionary's contents is "wrapped" with helper function the resets the flag and then chains to the normal dictionary method to actually perform the operation. Installing them into the class is simply a matter of putting the names of the methods in one of two lists and then passing them one at time to an auxiliary utility immediately following the creation of the class.

Categories