2015-11-04 71 views
5

考慮一個字符串'1234'。你需要一個產生所有旋轉的函數:'1234', '3412', '4123', '2341'。我創建了一個簡單的測試套件:生成字符串旋轉的Python方法

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

什麼是pythonic方式做到這一點?我的代碼完成下面

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

如果這是您認爲可以改進的**工作代碼**,請參閱[codereview.se]。 – jonrsharpe

+3

也許是一種理解? '{s [mid:] + s [:mid]爲範圍中的中間(len(s))}' –

+1

你有什麼是Pythonic足夠 - 儘管@ NiklasB。的評論,這也許應該是一個被接受的答案,可能更多(儘管在Python 2中用'xrange'替換'range') –

回答

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

你的第二個例子表明,如果數字是週期性你的做法是沒有效率的(例如123123123123)。作爲解決方案 - 檢查給定的旋轉是否已經出現。如果是這樣的 - 該序列是週期性的,你已經發現的所有區別的旋轉,所以才返回結果:

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 

(我改變了你的xrangerange,因爲我使用Python 3 - 你當然可以改變的背部)。

2

雖然絕對不是最快或最必要的Pythonic答案,但您可以使用collections.deque

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 

,並將其傳遞所有的示例測試:

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

我不會建議你對這個特定的問題使用collections.deque,但它可以應用於像這樣的更復雜的問題版本。這是一個非常有用的,在我看來,這是一個使用不足的工具 - 這就是爲什麼我把它作爲這個問題的答案。