Home > Software design >  Convert from integer to dictionary with repeating digits
Convert from integer to dictionary with repeating digits

Time:06-23

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]

Thanks in advance.

CodePudding user response:

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

CodePudding user response:

How about creating dict by default value list:

def dct_num(n):
    dct = {}
    str_n = str(n)
    for idx,i in enumerate(str_n):
        dct.setdefault(int(i), []).append(idx)
    return dct

for n in [123455, 941726149, 987385]:
    print(dct_num(n))

Output:

{1: [0], 2: [1], 3: [2], 4: [3], 5: [4, 5]}
{9: [0, 8], 4: [1, 7], 1: [2, 6], 7: [3], 2: [4], 6: [5]}
{9: [0], 8: [1, 4], 7: [2], 3: [3], 5: [5]}
  • Related