3

Consider the following list:

>>> circle = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']  
>>> list(enumerate(circle))  
[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd'), (4, 'e'), (5, 'f'), (6, 'g'), (7, 'h')]  

If circle is conceptualized as a circular list i.e. circle[0] is connected to circle[7], given a start index and an end index where start != end, I want to construct two lists that represent linear traversal orders in clockwise and counter-clockwise directions.

Depending on the values of start and end, here's what I have come up with:

Case 1: start < end

>>> circle = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']  
>>> start, end = 1, 6  
>>> clockwise = circle[start:end+1]  
>>> clockwise  
['b', 'c', 'd', 'e', 'f', 'g']  
>>> counter_clockwise = circle[start::-1] + circle[:end-1:-1]  
>>> counter_clockwise  
['b', 'a', 'h', 'g']  

Case 2: start > end

>>> circle = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']  
>>> start, end = 6, 1  
>>> clockwise = circle[start:] + circle[:end+1]  
>>> clockwise  
['g', 'h', 'a', 'b']  
>>> counter_clockwise = circle[start:end-1:-1]  
>>> counter_clockwise  
['g', 'f', 'e', 'd', 'c', 'b']  

Is there a pythonic/more-efficient/easier way of constructing these two lists?

2
  • I don't have an exact answer for you, but Numpy (numpy.org) has a bunch of useful features in their array implementation. Commented May 18, 2017 at 4:51
  • @Xorgon Sorry, not allowed to use Numpy. Commented May 18, 2017 at 5:13

4 Answers 4

3

You can use itertools.cycle:

import itertools

circle = ['a', 'b', 'c', 'd', 'e', 'f', 
  'g', 'h']

def clockwise(start, end):
    endless = itertools.cycle(circle)
    if start > end:
        end = start + (len(circle)-(start
          -end))
    return [next(endless) for i in range
      (end+1)][start:]

def counter_clockwise(start, end):
    endless = itertools.cycle(circle)
    if end > start:
        start = end + (len(circle)-(end
          -start))    
    return [next(endless) for i in range
      (start+1)][end:][::-1]

# start < end:
forward=clockwise(1, 6)
b1=counter_clockwise(1, 6)
#start > end:
f1=clockwise(6, 1)
backward=counter_clockwise(6, 1)

print(forward)
print(b1)
print(f1)
print(backward)

Outputs:

['b', 'c', 'd', 'e', 'f', 'g']
['b', 'a', 'h', 'g']
['g', 'h', 'a', 'b']
['g', 'f', 'e', 'd', 'c', 'b']
Sign up to request clarification or add additional context in comments.

1 Comment

But what about the case when start > end?
1
import itertools

def slice_it(circle,start,end,step=1):
    if end < start and step > 0:
        end = len(circle)+end
    if step < 0:
        return list(itertools.islice(itertools.cycle(circle),end,start,-1*step))[::-1]
    return list(itertools.islice(itertools.cycle(circle),start,end,step))

circle = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

print slice_it(circle,6,1)
print slice_it(circle,6,1,-1)

maybe?

Comments

0

You can use lambda expression for creating clockwise and anticlockwise methods and list slicing!

>>> clockwise = lambda circle, start, end: circle[start:] + circle[:end+1] if start > end else circle[start:end+1]
>>> counter_clockwise = lambda circle, start, end : clockwise(circle, end, start)[::-1]

This is somewhat similar to what you've tried, but in a more pythonic way and generalized way!

>>> clockwise(circle,1,6)
['b', 'c', 'd', 'e', 'f', 'g']
>>> counter_clockwise(circle,1,6)
['b', 'a', 'h', 'g']
>>> clockwise(circle,6,1)
['g', 'h', 'a', 'b']
>>> counter_clockwise(circle,6,1)
['g', 'f', 'e', 'd', 'c', 'b']

Comments

0

You can use deque from collections module to handle some parts of the counter_clockwise conditon like this example (you can modify it or improve it if you want):

from collections import deque

circle = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']


clockwise = lambda x,start,end: x[start:end+1] if start < end else x[start:] + x[:end+1]

def counter_clockwise(itertable, start, end):
    if end > start:
        a = deque(itertable[:start+1])
        b = deque(itertable[end:])
        a.rotate()
        b.rotate()
        # Or:
        # return list(a.__iadd__(b))
        return list(a) + list(b)

    if end < start:
        return itertable[start:end-1:-1]


print("start > end:")
start, end = 6,1
print(clockwise(circle, start, end))
print(counter_clockwise(circle, start, end))

print("start < end:")
start, end = 1,6
print(clockwise(circle, start, end))
print(counter_clockwise(circle, start, end))

Output:

start > end:
['g', 'h', 'a', 'b']
['g', 'f', 'e', 'd', 'c', 'b']
start < end:
['b', 'c', 'd', 'e', 'f', 'g']
['b', 'a', 'h', 'g']

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.