from itertools import product
import unittest
class QuadKeyGenerator:
def __init__(self, width):
self.width = width
self.odometerValues = [0] * self.width # max limit for each value on the odometer
#--- odometer approach iterative ---
def getNext(self):
l = self.width-1
i = 1
while l >= 0 and i !=0:
self.odometerValues[l] = ((self.odometerValues[l]+1) % self.width) # Odometer resets after reaching 3 to 0
if self.odometerValues[l] == 0:
i = 1
else:
i = 0
l = l - 1
if i != 0 and l < 0:
return False
return True
def generateQuadKeys(self):
while True:
yield "".join(str(i) for i in self.odometerValues)
if self.getNext() == False:
break
#--- recursive approach ---
def generateQK(self, qk, level):
if level == 0:
yield qk
else:
for i in range(self.width): # QuadKey
backUp = qk
qk = qk + str(i)
for g in self.generateQK(qk, level -1):
yield g
qk = backUp
#--- itertools approach ---
def generateQKItertools(self):
s = [x for x in range(self.width)]
p = product(s, repeat=self.width)
for qk in p:
yield ''.join(map(str, qk))
class QuadKeyGeneratorTest(unittest.TestCase):
def test_quadKeys_10(self):
width = 4
qkg = QuadKeyGenerator(width)
nonIterGen = qkg.generateQuadKeys()
recurGen = qkg.generateQK("", 4)
iterGen = qkg.generateQKItertools()
for x in range(width**4):
nonIterQK = nonIterGen.next()
recurQK = recurGen.next()
iterQK = iterGen.next()
self.assertTrue(nonIterQK == recurQK and recurQK == iterQK)
if __name__ == "__main__":
unittest.main()