2017-05-18 4 views
2

Tenir compte de la liste suivante:Créer deux listes linéaires à partir d'une liste circulaire conceptuelle en python

>>> 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')] 

Si circle est conceptualisée comme une liste circulaire c.-à-circle[0] est connecté à circle[7], étant donné un indice start et un indice endstart != end, Je veux construire deux listes qui représentent des ordres de traversée linéaire dans le sens des aiguilles d'une montre et dans le sens inverse des aiguilles d'une montre.

En fonction des valeurs de start et end, voici ce que je suis venu avec:

Cas 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'] 

Cas n ° 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'] 

Y at-il un pythonique/plus efficace/plus facile de construire ces deux listes?

+0

Je n'ai pas de réponse exacte pour vous, mais Numpy (http://www.numpy.org/) a un tas de fonctionnalités utiles dans leur implémentation de tableau. – Xorgon

+0

@Xorgon Désolé, pas autorisé à utiliser Numpy. – veritasium42

Répondre

3

Vous pouvez utiliser 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) 

Sorties:

['b', 'c', 'd', 'e', 'f', 'g'] 
['b', 'a', 'h', 'g'] 
['g', 'h', 'a', 'b'] 
['g', 'f', 'e', 'd', 'c', 'b'] 
+0

Mais qu'en est-il du cas où start> end? – kuro

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) 

peut-être?

0

Vous pouvez utiliser l'expression lambda pour créer des méthodes dans le sens des aiguilles d'une montre et dans le sens contraire des aiguilles d'une montre et pour lister des listes!

>>> 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] 

C'est un peu semblable à ce que vous avez essayé, mais d'une manière plus pythonique et de manière généralisée!

>>> 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'] 
0

Vous pouvez utiliser deque du module collections pour traiter certaines parties du counter_clockwise conditon comme cet exemple (vous pouvez le modifier ou l'améliorer si vous voulez):

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)) 

Sortie:

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