Preparation

The iteratorprotocol1 in Python prescribes that iterator objects must support the two following methods:

iterator.__iter__()

Prints the iterator object itself. This method is required, so that both compound data types and iterators can be used in for and in statements.

iterator.__next__()

Prints the next element from that iteration. If no elements are left, a StopIteration exception should be shown.

The example below illustrates how the class Reverse can be initialized with a sequence object (e.g. a string or a list). This class is an iterator that can be used to run through the elements in a sequence object in reverse order.

class Reverse:
    
    """
    >>> for element in Reverse('python'):
    ...     print(element, end='')
    nohtyp
    >>> for element in Reverse([1, 2, 3, 4]):
    ...     print(element, end='')
    4321
    """
    
    def __init__(self, container):
        
        self.container = container
        self.index = len(container)
        
    def __iter__(self):
        
        return self
    
    def __next__(self):
        
        if self.index > 0:
            self.index -= 1
            return self.container[self.index]
        else:
            raise StopIteration

Problem

Find for a given integer the next number that is larger and can be formed with the same digits. Suppose that the number given is 38276, then 38627 is the first number that is larger and can be formed by the digits 2, 3, 6, 7 and 8.

Suppose we start from the number 135798642, we can find the first following number that is larger and is formed with the same digits using the following algorithm. Split the first number in two parts, where the right part consists of the longest possible non-increasing sequence of digits one after another of the given number: 1357 98642. In other words, there is no digit in the right part that is smaller than the digit that follows. However, two consecutive digits can be equal. If the first part does not contain any digits — or in other words, if the given number is already a non-increasing sequence of digits — no larger number formed with the same digits can be found.

After that, search in the second part for the position of the smallest digit that is larger than the last digit of the first part (leftmost position if this smallest digits occurs more than once in the second part), and change the positions of these two digits. In our example, 7 is the last digit of the first part, and the first following larger digit of the second part is 8 on the second position. After changing places, we get 1358 97642. Lastly, we inverse the order of the digits in the second part and we put both parts back together:

Assignment

Write a class DigitPermutation of which the objects are initialized with a given integer. Objects of this class are iterators that follow the Python iterator protocol. For every iteration, the first integer is printed that is larger than the digit before and can be written with the same digit combination.

Example

>>> iter = DigitPermutation(135798642)
>>> next(iter)
135824679
>>> next(iter)
135824697

>>> iter = DigitPermutation(123)
>>> for first in iter:
...     print(first)
132
213
231
312
321