Search code examples
pythondictionarydata-structureshashmap

Convert from integer to dictionary with repeating digits


I need to take an integer n and add all its digits into a Python dictionary (hashtable) to later access them with an O(1) complexity.

n = 941726149

d = {}
for i in str(n):
    d[i] = None
print(d)

The problem is when there are repeating digits, the dictionary overrides them changing its order. For example, the above code outputs:

{'9': None, '4': None, '1': None, '7': None, '2': None, '6': None}

But the output I need is :

{'9': None, '4': None, '1': None, '7': None, '2': None, '6': None, '1': None, '4': None, '9': None}

I know it's impossible to add repeating keys into a hashtable, so I'm wondering if that data structure can be modified to fit this behavior, or use another (maybe custom) structure that supports it.

Edit

Example input and output:

  • n = 123455 d[5] = [4, 5]
  • n = 987385 d[8] = [1, 4] | d[9] = [0]

Solution

  • Here's an example, that for each digit present in the number, it stores its indexes.
    As a note, digits not present in the number won't be present in the structure either, so trying to index them (structure[digit_not_existing_in_number]) will yield KeyError (that's why dict.get is required). But that can be easily fixed.

    code00.py:

    #!/usr/bin/env python
    
    import sys
    
    
    def o1_access_structure(n):
        ret = {}
        for i, e in enumerate(str(n)):
            ret.setdefault(int(e), []).append(i)
        return ret
    
    
    def main(*argv):
        ns = (
            123455,
            987385,
            941726149,
        )
    
        for n in ns:
            print("\n", n)
            s = o1_access_structure(n)
            for e in range(10):
                print("  ", e, s.get(e))
    
    
    if __name__ == "__main__":
        print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
                                                       64 if sys.maxsize > 0x100000000 else 32, sys.platform))
        rc = main(*sys.argv[1:])
        print("\nDone.")
        sys.exit(rc)
    

    Output:

    [cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q072713761]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe" ./code00.py
    Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32
    
    
     123455
       0 None
       1 [0]
       2 [1]
       3 [2]
       4 [3]
       5 [4, 5]
       6 None
       7 None
       8 None
       9 None
    
     987385
       0 None
       1 None
       2 None
       3 [3]
       4 None
       5 [5]
       6 None
       7 [2]
       8 [1, 4]
       9 [0]
    
     941726149
       0 None
       1 [2, 6]
       2 [4]
       3 None
       4 [1, 7]
       5 None
       6 [5]
       7 [3]
       8 None
       9 [0, 8]
    
    Done.
    

    Or, if you don't care about the digit indexes, but only their presence / frequency, you could use [Python.Docs]: class collections.Counter([iterable-or-mapping]):

    >>> from collections import Counter
    >>>
    >>>
    >>> c = Counter(int(e) for e in str(941726149))
    >>>
    >>> for e in range(10):
    ...     print(e, c[e])
    ...
    0 0
    1 2
    2 1
    3 0
    4 2
    5 0
    6 1
    7 1
    8 0
    9 2