2014-05-17 135 views
4

我想做一個函數,我給它一個數字,函數返回從1到該數字的螺旋(2維數組)。例如,如果我將數字25賦予該函數,它將返回如下所示的內容:
enter image description here
我嘗試了不同的方法,但沒有解決。我只是不知道。
希望我解釋清楚自己。如何在python中製作螺旋?

+2

聽起來像家庭作業 - 請張貼你試過的東西,即使它不起作用。 – martineau

+0

這真的不是作業..只是爲了好玩.. – Skizo

+0

數字可以是任何?說,如果你給23? –

回答

3

這個問題有幾個步驟。首先,建立一個網格。網格的大小將需要等於下一個更高的完美平方;例如,如果輸入23,則需要5(25)格,或者如果輸入31,則需要6格(36)。接下來,將數字序列的下一個值存儲在「當前位置」(即,中心)中。在每一步中,檢查基本方向並將「當前位置」移動到先前未填充的位置,該位置離中心最近,偏向東方(處理初始步驟,沒有區別在N,S,E,W)。繼續下去,直到迭代器完成。


編輯:我真的很喜歡這個問題,所以我就寫了一個很好的解決方案。自從我編寫Python以來就有點過了,所以這可能不是最優雅的,但是。

from functools import partial 
from math import ceil, sqrt 

def gen_grid(n): 
    grid_size = int(ceil(sqrt(n))) 
    return [[None for _ in range(grid_size)] for _ in range(grid_size)] 

def valid_coord(grid, coord): 
    try: 
    return grid[coord[0]][coord[1]] is None 
    except: 
    return False 

def origin(size): 
    adjustment = 1 if size % 2 == 0 else 0 
    return (size/2 - adjustment), (size/2 - adjustment) 

north = lambda y, x: (y - 1, x) 
south = lambda y, x: (y + 1, x) 
east = lambda y, x: (y, x + 1) 
west = lambda y, x: (y, x - 1) 

directions = lambda y, x: [east(y, x), south(y, x), west(y, x), north(y, x)] 
distance = lambda c, nxt: sqrt((c[0] - nxt[0]) ** 2 + (c[1] - nxt[1]) ** 2) 

def walk_grid(nums): 
    grid = gen_grid(len(nums)) 
    center = origin(len(grid[0])) 
    current_position = center 
    center_distance = partial(distance, center) 

    for n in nums: 
    y, x = current_position 
    grid[y][x] = n 
    unseen_points = [c for c in directions(y, x) if valid_coord(grid, c)] 
    if n != nums[-1]: 
     current_position = sorted(unseen_points, key=center_distance)[0] 

    return grid 

def print_grid(highest): 
    result = walk_grid(range(1, highest + 1)) 
    for row in result: 
    for col in row: 
     print "{:>4}".format(col if col is not None else ''), 
    print "\n" 

輸出示例:

In [2]: grid.print_grid(25) 
    21 22 23 24 25 

    20 7 8 9 10 

    19 6 1 2 11 

    18 5 4 3 12 

    17 16 15 14 13 
+0

這個問題已經關閉了,但我寫了一個解決方案,使用numpy和一個自定義的Vec2類,在這裏你有一個點和一個方向矢量,然後你添加它們。當你到達數組的末尾時,旋轉90度:'direction = Vec2(-direction.y,direction.x)'方向被初始化爲'Vec2(1,0)'這些都很有趣! (我的螺旋代碼從左上角開始,到達中心,只需將生成的列表顛倒即可!) – SapphireSun

0

所以我假設你已經可以以某種方式確定該陣列的尺寸和「一個」的位置。現在你需要一個允許你改變方向和計數器的功能。

def get_new_direction(direction): 
    switch direction: 
    case E: return S 
    case S: return W 
    case W: return N 
    case N: return E 

i,j = initial_coordinates_of_the_one 
direction = right 
steps = 1 
next_number = 1 

while not done: 
    place(next_number, i, j) 
    i,j = get_coordinates_after_move(direction, steps) 
    direction = get_new_direction(direction) 
    next_number++ 
    if iteration is even: 
    steps++ 

這只是一個草圖。什麼是人仍下落不明(但很容易弄清楚):

  • 如何實現功能
  • 如何設置多個號碼,而下面的一個方向
+0

另外,Python沒有'switch'語句或運算符'++'。 – Davidmh

+0

@Davidmh這顯然是僞代碼。 – poke

8

晴這裏的問題是枚舉座標之一 - 將數字與座標進行匹配,然後將其打印出來。

開始通過注意兩個基本模式:

  • (方向)向右移動,然後放下,然後離開,再向上,那麼......(這是希望明顯)
  • (幅度)移動一個,然後一個,然後兩個,然後兩個,然後三個...

因此,用這些規則,寫一個生成器,產生number, coordinates元組。

如果你先設置一些輔助函數,這是最清晰的;我會格外詳細:

def move_right(x,y): 
    return x+1, y 

def move_down(x,y): 
    return x,y-1 

def move_left(x,y): 
    return x-1,y 

def move_up(x,y): 
    return x,y+1 

moves = [move_right, move_down, move_left, move_up] 

很容易,現在的發電機:

def gen_points(end): 
    from itertools import cycle 
    _moves = cycle(moves) 
    n = 1 
    pos = 0,0 
    times_to_move = 1 

    yield n,pos 

    while True: 
     for _ in range(2): 
      move = next(_moves) 
      for _ in range(times_to_move): 
       if n >= end: 
        return 
       pos = move(*pos) 
       n+=1 
       yield n,pos 

     times_to_move+=1 

演示:

list(gen_points(25)) 
Out[59]: 
[(1, (0, 0)), 
(2, (1, 0)), 
(3, (1, -1)), 
(4, (0, -1)), 
(5, (-1, -1)), 
(6, (-1, 0)), 
(7, (-1, 1)), 
(8, (0, 1)), 
(9, (1, 1)), 
(10, (2, 1)), 
(11, (2, 0)), 
(12, (2, -1)), 
(13, (2, -2)), 
(14, (1, -2)), 
(15, (0, -2)), 
(16, (-1, -2)), 
(17, (-2, -2)), 
(18, (-2, -1)), 
(19, (-2, 0)), 
(20, (-2, 1)), 
(21, (-2, 2)), 
(22, (-1, 2)), 
(23, (0, 2)), 
(24, (1, 2)), 
(25, (2, 2))] 
4

這裏有一個圖表來幫助你思考問題:

enter image description here

你可以認爲這是多次加入到N×N的方盡的(N + 1)×(N + 1)方:

if N is odd: 
    move right one step 
    move down N steps 
    move left N steps 
else: 
    move left one step 
    move up N steps 
    move right N steps 

,並在你寫一個數到當前位置的每一步。正如@米蘭指出的那樣,你可能並不總是想要完成當前的shell(即如果你只想數到23)。要做到這一點最簡單的方法是使產生的步驟層出不窮發電機的功能,然後根據需要只消耗盡可能多的步驟:

from itertools import count 

def steps_from_center(): 
    for n in count(start=1): 
     if n % 2: 
      yield RIGHT 
      for i in range(n): 
       yield DOWN 
      for i in range(n): 
       yield LEFT 
     else: 
      yield LEFT 
      for i in range(n): 
       yield UP 
      for i in range(n): 
       yield RIGHT 

在此之前可以用我們必須決定如何存儲值,並基於此,如何表示UP,DOWN,LEFTRIGHT

最簡單的存儲是2d數組,或者用Python表示列表的列表。外部列表將保存輸出行,內部列表將保持行內的單元格,並且每個單元格可以被尋址爲my_array[y][x],x從左到右增加,y從頂部向下增加(這與我們期望打印輸出)。

這允許我們定義我們的方向:

from collections import namedtuple 

Step = namedtuple("Step", ["dx", "dy"]) 
RIGHT = Step(1, 0) 
DOWN = Step(0, 1) 
LEFT = Step(-1, 0) 
UP = Step(0, -1) 

之前,我們可以分配存儲空間,我們需要知道一個數組,我們有多大需要:

from math import ceil, floor, log10, sqrt 

max_i = int(input("What number do you want to display up to? ")) 

# how big does the square have to be? 
max_n = int(ceil(sqrt(max_i))) 

# here is our initialized data structure 
square = [[EMPTY] * max_n for _ in range(max_n)] 

# and we start by placing a 1 in the center: 
x = y = max_n // 2 
square[y][x] = output(1) 

我在這裏增加了兩個片:爲了使輸出整齊,每個項目應該打印相同的寬度。 output()是一個函數,它的值並返回正確寬度的字符串,EMPTY是該寬度的空格的字符串:

# how many digits in the largest number? 
max_i_width = int(floor(log10(max_i))) + 1 

# custom output formatter - make every item the same width 
def output(item, format_string="{{:>{}}}".format(max_i_width)): 
    return format_string.format(item) 

EMPTY = output("") 

現在的作品已經到位,我們可以產生螺旋:

for i, step in enumerate(steps_from_center(), start=2): 
    if i > max_i: 
     break 
    else: 
     x += step.dx 
     y += step.dy 
     square[y][x] = output(i) 

,並打印出來:

print("\n".join(" ".join(row) for row in square)) 

,它運行,如:

What number do you want to display up to? 79 
73 74 75 76 77 78 79  
72 43 44 45 46 47 48 49 50 
71 42 21 22 23 24 25 26 51 
70 41 20 7 8 9 10 27 52 
69 40 19 6 1 2 11 28 53 
68 39 18 5 4 3 12 29 54 
67 38 17 16 15 14 13 30 55 
66 37 36 35 34 33 32 31 56 
65 64 63 62 61 60 59 58 57