Python: Dictionary where key is tuple of unknown order
Question:
I am trying to find a way to create a dictionary so that I can map a list of values to an appropriate function.
For example, I have something that looks like:
function_map = {('Put','Put','Call','Call'): FunctionOne,
('Put','Call','Combo'): FunctionTwo,
('Call','Put'):FunctionThree,
('Put','Combo'):FunctionFour}
What I’m struggling with is how to deal with can a lookup value that can be in any permutation of the key.
For example, I might try to do function_map[(Call, Put, Call, Put)]
, and I would want this to return FunctionOne
. Or function_map[(Combo, Put)]
I would want FunctionFour
returned.
Any help is appreciated!
Answers:
A solution to your provided example could be something like this:
from itertools import permutations
function_map = {1: FunctionOne,
2: FunctionTwo,
3: FunctionThree,
4: FunctionFour}
permutations_map = {1: list(permutations(('Put', 'Put', 'Call', 'Call'))),
2: list(permutations(('Put', 'Call', 'Combo'))),
3: list(permutations(('Call', 'Put'))),
4: list(permutations(('Put', 'Combo')))}
def get_function(perm: tuple):
for key, value in permutations_map.items():
if perm in value:
return function_map[key]
function_output = get_function(('Call', 'Put', 'Call', 'Put'))()
where function_output
is the output of FunctionOne
.
If you run this code very frequently, the accepted answer is suboptimal because it computes the permutations each time you call it (making it slower), while this is just a lookup.
Try this:
import itertools as it
function_map = {('Put','Put','Call','Call'): FunctionOne,
('Put','Call','Combo'): FunctionTwo,
('Call','Put'): FunctionThree,
('Put','Combo'): FunctionFour}
def func_map(x):
for k, v in function_map.items():
if x in it.permutations(k):
return v
return False
func_map(('Combo', 'Put'))()
(Goes into FunctionFour)
If the value of each dictionary key can be unordered, you can sort each tuple to ensure the order is consistent.
Example
function_map = {
('Call', 'Call', 'Put', 'Put'): FunctionOne,
('Call', 'Combo', 'Put'): FunctionTwo,
('Call', 'Put'): FunctionThree,
('Combo', 'Put'): FunctionFour
}
In order to access the values of the dictionary, I recommend you to use .get
instead of accessing via [key]
. It avoids unexpected errors while trying to access not existing keys.
For your examples, you may call with the following statements:
function_map.get(tuple(sorted(('Call', 'Put', 'Call', 'Put'))))
# output: <function __main__.FunctionOne>
function_map.get(tuple(sorted(('Combo', 'Put'))))
# output: <function __main__.FunctionFour>
The output while accessing not existing key
function_map.get("not existing key")
#output: <None>
# If you need an other values while accessing not existing key
function_map.get("not existing key", "default value")
# output: 'default value'
@The Thonnu‘s answer is memory efficient but lookup complexity is fairly high. The simple alternative which I’ve mentioned in this comment is to map all possible permutations of every tuple to same function:
from itertools import permutations
function_map = (
dict.fromkeys(permutations(('Put', 'Put', 'Call', 'Call')), FunctionOne) |
dict.fromkeys(permutations(('Put', 'Put', 'Combo')), FunctionTwo) |
dict.fromkeys(permutations(('Call', 'Put')), FunctionThree) |
dict.fromkeys(permutations(('Put','Combo')), FunctionFour)
)
function_map['Call', 'Put', 'Call', 'Put']()
This option takes more time to generate mapping (around 10 times slower than regular dict
initialization) but it makes each lookup significantly faster (at least 10 times faster than lookup with function, benchmark code).
So if you will continuously search for function in this mapping, my answer is preferable.
Another alternative solution is to use .get(). It will solve your problem.
function_map.get(('Put','Combo'))
If you want to execute the function try:
function_map.get(('Put','Combo'))()
I am trying to find a way to create a dictionary so that I can map a list of values to an appropriate function.
For example, I have something that looks like:
function_map = {('Put','Put','Call','Call'): FunctionOne,
('Put','Call','Combo'): FunctionTwo,
('Call','Put'):FunctionThree,
('Put','Combo'):FunctionFour}
What I’m struggling with is how to deal with can a lookup value that can be in any permutation of the key.
For example, I might try to do function_map[(Call, Put, Call, Put)]
, and I would want this to return FunctionOne
. Or function_map[(Combo, Put)]
I would want FunctionFour
returned.
Any help is appreciated!
A solution to your provided example could be something like this:
from itertools import permutations
function_map = {1: FunctionOne,
2: FunctionTwo,
3: FunctionThree,
4: FunctionFour}
permutations_map = {1: list(permutations(('Put', 'Put', 'Call', 'Call'))),
2: list(permutations(('Put', 'Call', 'Combo'))),
3: list(permutations(('Call', 'Put'))),
4: list(permutations(('Put', 'Combo')))}
def get_function(perm: tuple):
for key, value in permutations_map.items():
if perm in value:
return function_map[key]
function_output = get_function(('Call', 'Put', 'Call', 'Put'))()
where function_output
is the output of FunctionOne
.
If you run this code very frequently, the accepted answer is suboptimal because it computes the permutations each time you call it (making it slower), while this is just a lookup.
Try this:
import itertools as it
function_map = {('Put','Put','Call','Call'): FunctionOne,
('Put','Call','Combo'): FunctionTwo,
('Call','Put'): FunctionThree,
('Put','Combo'): FunctionFour}
def func_map(x):
for k, v in function_map.items():
if x in it.permutations(k):
return v
return False
func_map(('Combo', 'Put'))()
(Goes into FunctionFour)
If the value of each dictionary key can be unordered, you can sort each tuple to ensure the order is consistent.
Example
function_map = {
('Call', 'Call', 'Put', 'Put'): FunctionOne,
('Call', 'Combo', 'Put'): FunctionTwo,
('Call', 'Put'): FunctionThree,
('Combo', 'Put'): FunctionFour
}
In order to access the values of the dictionary, I recommend you to use .get
instead of accessing via [key]
. It avoids unexpected errors while trying to access not existing keys.
For your examples, you may call with the following statements:
function_map.get(tuple(sorted(('Call', 'Put', 'Call', 'Put'))))
# output: <function __main__.FunctionOne>
function_map.get(tuple(sorted(('Combo', 'Put'))))
# output: <function __main__.FunctionFour>
The output while accessing not existing key
function_map.get("not existing key")
#output: <None>
# If you need an other values while accessing not existing key
function_map.get("not existing key", "default value")
# output: 'default value'
@The Thonnu‘s answer is memory efficient but lookup complexity is fairly high. The simple alternative which I’ve mentioned in this comment is to map all possible permutations of every tuple to same function:
from itertools import permutations
function_map = (
dict.fromkeys(permutations(('Put', 'Put', 'Call', 'Call')), FunctionOne) |
dict.fromkeys(permutations(('Put', 'Put', 'Combo')), FunctionTwo) |
dict.fromkeys(permutations(('Call', 'Put')), FunctionThree) |
dict.fromkeys(permutations(('Put','Combo')), FunctionFour)
)
function_map['Call', 'Put', 'Call', 'Put']()
This option takes more time to generate mapping (around 10 times slower than regular dict
initialization) but it makes each lookup significantly faster (at least 10 times faster than lookup with function, benchmark code).
So if you will continuously search for function in this mapping, my answer is preferable.
Another alternative solution is to use .get(). It will solve your problem.
function_map.get(('Put','Combo'))
If you want to execute the function try:
function_map.get(('Put','Combo'))()