Question: I currently have a class which stores a list of lists. The inner lists are not of the same length. I made the class subscriptable with the following code (possibly not the best way of doing this, and perhaps overly fancy). class MyClass: def __init__(self): # self.instructions = [] # for demo purposes self.instructions.append([0, 1, 2]) self.instructions.append([3, 4, 5, 6]) self.instructions.append([7, 8]) def __getitem__(self, ind): if ind >= 0: iterator = self.instructions.__iter__() compare = int.__gt__ inc = int.__add__ else: iterator = reversed(self.instructions) compare = int.__le__ inc = int.__sub__ s = 0 for tp in iterator: L = len(tp) if compare(inc(s, L), ind): return tp[ind-s] else: s = inc(s, L) else: raise IndexError('index out of range')  This works. For instance >>> x = MyClass() >>> x[5] 5 >>> x[-5] 4  Now, I need to modify the class so it now stores two list of lists. The two lists are instructions and annotations, and both have the same length. But len(instructions[i]) does not have to equal len(annotations[i]). class NewClass: def __init__(self): # self.instructions = [] self.annotations = [] # for demo purposes self.instructions.append([0, 1, 2]) self.instructions.append([5, 6, 7, 8]) self.instructions.append([12, 13]) self.annotations.append([3, 4]) self.annotations.append([9, 10, 11]) self.annotations.append([14, 15, 16]) def __getitem__(self, ind): pass  I want to make this subscriptable, with the order of elements oscillating between the instructions sublists and the annotations sublists. The demo data indicates the subscripting order. I want >>> y = NewClass() >>> y[9] 9 >>> y[-4] 13  What's an efficient way of doing this? I could write a solution where I alternatively iterate through the two sublists. But I feel like I am straying far from the correct solution. I am also looking for a non-for-loop solution as I am dealing with long lists.

Answer: While your implementation is nice, I would like to share my own way for iterating using chain.from_iterable. Because basically we're chaining the items whether from the beginning or at the end. For one list: The only part that needs explanation is map(reversed, reversed(self.instructions)). We not only need to reverse the whole list, but also the individual sublists. from itertools import chain class MyClass: def __init__(self): self.instructions = [ [0, 1, 2], [3, 4, 5, 6], [7, 8], ] def __getitem__(self, ind): if ind >= 0: chunks = self.instructions range_parameter = ind + 1 else: chunks = map(reversed, reversed(self.instructions)) range_parameter = abs(ind) iterator = chain.from_iterable(chunks) try: for _ in range(range_parameter): n = next(iterator) except StopIteration: raise IndexError("index out of range") return n x = MyClass() print(x[5]) print(x[-5])  For two lists: Since you said we need to oscillate, zip is the right tool for that. When ind is positive it's straightforward. We zip them and use chain.from_iterable two times because otherwise it gives us individual sub-lists. If ind is negative, we need two reversed() before zipping. One for outer lists, and one for sublists. from itertools import chain class MyClass: def __init__(self): self.instructions = [ [0, 1, 2], [5, 6, 7, 8], [12, 13], ] self.annotations = [ [3, 4], [9, 10, 11], [14, 15, 16], ] def __getitem__(self, ind): if ind >= 0: chunks = zip(self.instructions, self.annotations) range_parameter = ind + 1 else: chunks = zip( map(reversed, reversed(self.annotations)), map(reversed, reversed(self.instructions)), ) range_parameter = abs(ind) iterator = chain.from_iterable(chain.from_iterable(chunks)) try: for _ in range(range_parameter): n = next(iterator) except StopIteration: raise IndexError("index out of range") return n x = MyClass() print(x[9]) print(x[-4])