How to Create a Circular List in Python

1 min read 336 words

The challenge

Create a Circular List

A circular list is of finite size, but can infititely be asked for its previous and next elements. This is because it acts like it is joined at the ends and loops around.

For example, imagine a CircularList of [1, 2, 3, 4]. Five invocations of next() in a row should return 1, 2, 3, 4 and then 1 again. At this point, five invocations of prev() in a row should return 4, 3, 2, 1 and then 4 again.

Your CircularList is created by passing a vargargs parameter in, e.g. new CircularList(1, 2, 3). Your list constructor/init code should throw an Exception if nothing is passed in.

The solution in Python code

Option 1:

class CircularList():
    def __init__(self, *args):
        self.l=[v for v in args]
        if not self.l:
            raise Exception("")
        self.i=-1
        
    def next(self):
        self.i=self.i+1
        self.i=self.i if len(self.l)>self.i else 0
        return self.l[self.i]
    
    def prev(self):
        self.i=self.i-1
        self.i=self.i if self.i>=0 else len(self.l)-1
        return self.l[self.i]

Option 2:

class CircularList(list):
    def __init__(self, *args):
        if not args: raise
        self.lst = args
        
    def next(self):
        try: self.i += 1
        except: self.i = 0
        return self.lst[self.i%len(self.lst)]
    
    def prev(self):
        try: self.i -=1
        except: self.i = -1
        return self.lst[self.i%len(self.lst)]

Option 3:

class CircularList():
    def __init__(self, *args):
        if not args:
            raise ValueError
        self.arg = args
        self.index = None
        self.max_index = len(args) - 1
        
    def next(self):
        if self.index is None or self.index == self.max_index:
            self.index = 0
        else:
            self.index += 1        
        return self.arg[self.index]
    
    def prev(self):
        if self.index is None or self.index == 0:
            self.index = self.max_index
        else:
            self.index -= 1
        return self.arg[self.index]

Test cases to validate our solution

import test
import solution # or from solution import example

# test.assert_equals(actual, expected, [optional] message)
@test.describe("Fixed Tests")
def test_group():
    @test.it("test circular string list")
    def test_case():
        list = CircularList("one", "two", "three")
        test.assert_equals(list.next(), "one")
        test.assert_equals(list.next(), "two")
        test.assert_equals(list.next(), "three")
        test.assert_equals(list.next(), "one")
        test.assert_equals(list.prev(), "three")
        test.assert_equals(list.prev(), "two")
        test.assert_equals(list.prev(), "one")
        test.assert_equals(list.prev(), "three")
        
    @test.it("test circular integer list")
    def test_case_2():
        list = CircularList(1, 2, 3, 4, 5)
        test.assert_equals(list.prev(), 5)
        test.assert_equals(list.prev(), 4)
        test.assert_equals(list.next(), 5)
        test.assert_equals(list.next(), 1)
        test.assert_equals(list.prev(), 5)
        test.assert_equals(list.prev(), 4)
        test.assert_equals(list.prev(), 3)
        test.assert_equals(list.prev(), 2)
Tags:
Andrew
Andrew

Andrew is a visionary software engineer and DevOps expert with a proven track record of delivering cutting-edge solutions that drive innovation at Ataiva.com. As a leader on numerous high-profile projects, Andrew brings his exceptional technical expertise and collaborative leadership skills to the table, fostering a culture of agility and excellence within the team. With a passion for architecting scalable systems, automating workflows, and empowering teams, Andrew is a sought-after authority in the field of software development and DevOps.

Tags