Home > Software engineering >  Tuples as dict keys where order may not always matter
Tuples as dict keys where order may not always matter

Time:05-06

I have a dictionary that uses tuples as keys. The keys refer to edges between two nodes on a graph eg. "vendor connects to account" and the associated value is the strength of the connection so ('vendor','account'): 7. I need to be able to get the values from the dictionary in two ways: a) by passing in the key where the order of elements in the tuple is important b) where the order of the tuple is not important. The difference is that sometimes the direction of the connection matters and sometimes it doesn't. (In graph terms sometimes I consider the graph directed and sometimes undirected.) Note that there are no duplicate tuple pairs eg. (vendor,account) - (account,vendor) so that makes things easier.

I came up with a way of accepting a tuple and matching it to the correct key regardless of order. Unfortunately it means looping through all the keys every time. I'm just wondering if there is a better way?

v_dict = {('vendor', 'account'):1,
        ('vendor', 'cost_center'):2,
        ('vendor', 'purchase_order'):3,
        ('vendor', 'user_name'):5,
        ('vendor', 'invoice'):6}

pair = [('purchase_order', 'vendor'), ('invoice','vendor'), ('vendor', 'user_name')]

key = []

[key.append(j) for j in v_dict.keys() for i in pair if i[0] in j and i[1] in j]

for key in key:
    print(key, v_dict[key])

Note: I'm aware of and work with dedicated graph libraries. In this instance I have to use just python.

CodePudding user response:

I see two approaches:

  1. Sort the tuple before attempting to use it as an index. That way, the order you get the tuple in doesn't matter.

    v_dict = {('vendor', 'account'):1,
            ('vendor', 'cost_center'):2,
            ('vendor', 'purchase_order'):3,
            ('vendor', 'user_name'):5,
            ('vendor', 'invoice'):6}
    
    v_dict = {tuple(sorted(k)): v for k, v in v_dict.items()}
    
    def get_vdict_value(key):
        return v_dict.get(tuple(sorted(key)))
    
  2. Use a frozenset of your tuple as your key.

    v_dict = {frozenset(k): v for k, v in v_dict.items()}
    
    def get_vdict_value(key):
        return v_dict.get(frozenset(key))
    
    

Use the function we just defined to fix the key before getting it from the dict.

pairs = [('purchase_order', 'vendor'), ('invoice','vendor'), ('vendor', 'user_name')]

for pair in pairs:
    print(pair, get_vdict_value(pair))

# ('purchase_order', 'vendor') 3
# ('invoice', 'vendor') 6
# ('vendor', 'user_name') 5
  • Related