2015-11-04 19 views
5

Considerare una stringa '1234'. È necessaria una funzione che genera tutte le rotazioni: '1234', '3412', '4123', '2341'. Ho creato una semplice suite di test:Modo Pythonic per generare rotazioni di stringhe

assert rotations('123') == set(['123', '231', '312']) 
assert rotations('111') == set(['111']) 
assert rotations('197') == set(['197', '971', '719']) 

Qual è il modo pitone per farlo? Ho finito con codice sotto

def rotations(num): 
    str_num = str(num) 
    result = set() 
    for mid in xrange(len(str_num)): 
     result.add(
      str_num[mid:] + str_num[:mid] 
     ) 
    return result 
+3

Se questo è ** codice di lavoro ** che si ritiene possa essere migliorato, consultare [codereview.se]. – jonrsharpe

+3

forse un insieme di comprensione? '{s [mid:] + s [: mid] per il medio di gamma (len (s))}' –

+1

Quello che hai è abbastanza pitone - anche se il commento di @ NiklasB., che forse merita di essere una risposta accettata , probabilmente lo è di più (sebbene sostituisca 'range' di' xrange' in Python 2) –

risposta

3
s='1234' 
z = {s[x:]+s[:x] for x in range(len(s))} 
3

Il secondo esempio suggerisce che il metodo non è efficace se il numero è periodica (ad esempio 123.123.123.123). Come soluzione: controlla se una determinata rotazione è già apparsa. Se è così - la sequenza è periodica e di aver già scoperto tutte le rotazioni distinguibili, quindi basta restituire il risultato:

def rotations(num): 
    str_num = str(num) 
    result = set() 
    for mid in range(len(str_num)): 
     rot = str_num[mid:] + str_num[:mid] 
     if rot in result: 
      return result 
     else: 
      result.add(rot) 
    return result 

(ho cambiato il tuo xrange a range dal momento che sto usando Python 3 - si può di cambio di rotta indietro).

2

Anche se sicuramente non è la risposta più veloce o necessariamente più Pythonic, è possibile utilizzare collections.deque per questo.

from collections import deque 

def rotations(s): 
    s_dq = deque(s) 
    result = set() 
    for _ in xrange(len(s_dq)): 
     s_dq.rotate(1) 
     result.add(''.join(s_dq)) 
    return result 

e passa tutti i test di esempio:

def main(): 
    tests = ['123', 
      '111', 
      '197'] 

    desired = [set(['123', '231', '312']), 
       set(['111']), 
       set(['197', '971', '719'])] 

    for test, result in zip(tests, desired): 
     print rotations(test) == result 

if __name__ == '__main__': 
    main() 

Vero

Vero

Vero

non vorrei raccomandare che si usa collections.deque per questo particolare problema, ma può essere applicato a versioni più complicate di problemi come questo. È uno strumento molto utile e, a mio parere, sottoutilizzato - è per questo che l'ho incluso come risposta a questa domanda.

Problemi correlati