2

Consider I have two groups of string elements (unnecessary string - just for the example): "strA1, strA2, strA3" and "strB1, strB2, strB3". I'd like to map elements from the first list with elements from the second list into unique pairs by known law that I can find element in the second list by element in the first list and visa versa.
I know three methods to do it.

Method 1.: Create a map

{'strA1':'strB1', 'strA2':'strB2', 'strA3':'strB3'}

In this case I can find an element from the second list just by key. But if I want to find element from the first list I have to iterate through all dictionary keys.

Method 2.: Create two maps:

{'strA1':'strB1', 'strA2':'strB2', 'strA3':'strB3'}

{'strB1':'strA1', 'strB2':'strA2', 'strB3':'strA3'}

In this case I can find an element by key in both lists but I have to keep two maps for that.

Method 3: Create meaningful indexes (manually or with enum) and use a special parameter to select an element from the pair in a tuple:

from enum import Enum
Index = Enum('Index', ['PAIR_A1B1', 'PAIR_A2B2', 'PAIR_A3B3'], start=0)  #understandable names
 #direction
A2B = 0
B2A = 1   
mappingList = [('strA1','strB1'), ('strA2','strB2'), ('strA3','strB3')]
print(mappingList[Index.PAIR_A1B1.value][A2B]) # I get my mapped string here

Are there another methods?

MrNobody33
  • 6,413
  • 7
  • 19

2 Answers2

1

You could try with bidict library too:

from bidict import bidict

group1=["strA1", "strA2", "strA3"]   
group2=["strB1", "strB2", "strB3"]
    
dc=dict(zip(group1,group2))   #we create the dictionary by using zip to create the tuples and then cast it to a dict
    
newdc= bidict(dc)             #we create the bi-directional dictionary

print(newdc['strA1'])
print(newdc.inverse['strB1'])

Output:

strB1
strA1
MrNobody33
  • 6,413
  • 7
  • 19
1

The forward and reverse mappings are probably your best option. Here is a way that you could access them via a single object (subclass of dictionary with a reversed dictionary added).

Obviously it will still need to allocate the memory, although the two dictionaries will use references to the same objects contained within them, rather than duplicated objects.

class Map(dict):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._reversed = dict((v, k) for k, v in self.items())
        if len(self) != len(self._reversed):
            raise ValueError("values not unique")

    def __setitem__(self, k, v):
        if v in self._reversed:
            raise ValueError("attempted item assignment would create many-to-one mapping")        
        if k in self:
            # reassigning - need to delete reversed key first
            del self._reversed[self[k]]  # or just "del self[k]" here
        super().__setitem__(k, v)
        self._reversed[v] = k

    def __delitem__(self, k):
        del self._reversed[self[k]]
        super().__delitem__(k)

    def get_reversed(self, v):
        return self._reversed[v]


if __name__ == '__main__':

    a = Map({'strA1':'strB1', 'strA2':'strB2', 'strA3':'strB3'})

    a["strA4"] = "strB4"
    a["strA5"] = "strB5"

    # in each of forward and reversed direction, test
    # one of the pairs that we started with, and one of 
    # the pairs that we added afterwards

    for k in "strA2", "strA4":
        print(a[k])

    for k in "strB3", "strB5":
        print(a.get_reversed(k))

gives:

strB2
strB4
strA3
strA5

It would need

alani
  • 12,573
  • 2
  • 13
  • 23