2009-10-25 11 views
8

Mam listę list, coś w rodzajuOkreślanie sąsiadów dwuwymiarowej listy komórek

[[1, 2, 3,],[4, 5, 6,],[7, 8, 9]].

przedstawić w formie graficznej jak:

1 2 3 
4 5 6 
7 8 9 

szukam eleganckim podejście do sprawdzania wartości sąsiadów komórce, poziomo, pionowo i na ukos. Na przykład, sąsiadami [0] [2] są [0] [1], [1] [1] i [1] [2] lub liczby 2, 5, 6.

Teraz zdaję sobie sprawę, że ja może po prostu zrobić ataku Bruteforce kontrolowanie każdej wartości a la:

[i-1][j] 
[i][j-1] 
[i-1][j-1] 
[i+1][j] 
[i][j+1] 
[i+1][j+1] 
[i+1][j-1] 
[i-1][j+1] 

Ale to łatwe, i pomyślałem, mogę dowiedzieć się więcej, widząc jakieś bardziej eleganckie podejść.

+0

Czy chcesz uzyskać indeksy lub wartości? I czy chcesz funkcji, która może wykonywać losowy dostęp do każdego indeksu lub funkcji, która zwraca listę par (val, sąsiedzi_z_val)? - Po prostu uzyskanie indeksów jest zbyt proste, aby uzyskać eleganckie rozwiązanie, ale to, co naprawdę chcesz zrobić, może być ciekawsze. –

+1

Albo - celowo zostawiłem to pytanie dość ogólnie, aby ludzie nie czuli się ograniczeni. –

Odpowiedz

15
# Size of "board" 
X = 10 
Y = 10 

neighbors = lambda x, y : [(x2, y2) for x2 in range(x-1, x+2) 
           for y2 in range(y-1, y+2) 
           if (-1 < x <= X and 
            -1 < y <= Y and 
            (x != x2 or y != y2) and 
            (0 <= x2 <= X) and 
            (0 <= y2 <= Y))] 

>>> print(neighbors(5, 5)) 
[(4, 4), (4, 5), (4, 6), (5, 4), (5, 6), (6, 4), (6, 5), (6, 6)] 

Nie wiem, czy to jest uważane za czyste, ale ten jeden-liner daje wszystkie sąsiadów przez powtarzanie w ciągu je i odrzucając wszelkie przypadki brzegowe.

+0

Co się stanie, jeśli "tablica" to "10201x10201"? – FaCoffee

+0

@ CF84: Zatem stałe "X" i "Y" będą musiały mieć przypisane różne wartości. Masz problem w związku z tym - o co ci chodzi? – martineau

+0

@CDspace, w jaki sposób edycja różni się od pierwotnej intencji postu? Jeśli masz na myśli jeden liniowiec, może on nadal być zapisany w jednej linii z normalną funkcją. Co więcej, od poprzedniej edycji nie był on ani jednym linerem. Co najmniej wielkie zmienne X i Y powinny zostać zmienione, ponieważ są trudne do wykrycia. – skrx

1

Oto lista:

(x - 1, y - 1) (x, y - 1) (x + 1, y - 1) 
(x - 1, y)  (x, y)  (x + 1, y) 
(x - 1, y + 1) (x, y + 1) (x + 1, y + 1) 

Więc poziome sąsiedzi (x, y) jest (+/- 1 x, y).

Pionowe sąsiedzi to (x, y +/- 1).

Sąsiadujące ukośne to (x +/- 1, y +/- 1).

Te zasady dotyczą nieskończonej macierzy. Aby upewnić się, że sąsiedzi pasują do skończonej macierzy, jeśli początkowy (x, y) znajduje się na krawędzi, zastosuj jeszcze jedno ograniczenie do współrzędnych sąsiadów - rozmiaru matrycy.

2

Nie ma prostszego sposobu na zrobienie tego. Jeśli naprawdę chcesz, możesz utworzyć funkcję:

def top(matrix, x, y): 
    try: 
     return matrix[x][y - 1]; 
    except IndexError: 
     return None 
+0

'except IndexError' – u0b34a0f6ae

+0

@ Kaizer.se: Dzięki, nie byłem pewien, który to był i zbyt leniwy, aby go sprawdzić lub wypróbować. –

+0

+1 to nie jest kompletne rozwiązanie, ale interesujące, ponieważ może to być dość Pythoniczny sposób wyszukiwania sąsiadów - to jest EAFP – u0b34a0f6ae

0
>>> import itertools 
>>> def sl(lst, i, j): 
    il, iu = max(0, i-1), min(len(lst)-1, i+1) 
    jl, ju = max(0, j-1), min(len(lst[0])-1, j+1) 
    return (il, iu), (jl, ju) 

>>> lst = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] 
>>> tup = 0, 2 
>>> [lst[i][j] for i, j in itertools.product(*sl(lst, *tup)) if (i, j) != tup] 
[2, 5, 6] 

nie wiem jak elegancki wydaje się wam, ale wydaje się, aby pracować w/o każdy ciężko kodowania.

3
for x_ in range(max(0,x-1),min(width,x+2)): 
    for y_ in range(max(0,y-1),min(height,y+2)): 
    if (x,y)==(x_,y_): continue 
    # do stuff with the neighbours 

>>> a=[[1, 2, 3], [4, 5, 6], [7, 8, 9]] 
>>> width=height=3 
>>> x,y=0,2 
>>> for x_ in range(max(0,x-1),min(width,x+2)): 
... for y_ in range(max(0,y-1),min(height,y+2)): 
...  if (x,y)==(x_,y_): continue 
...  print a[x_][y_] 
... 
2 
5 
6 
0

Generuje wszystkie indeksy:

def neighboring(array): 
    nn,mm = len(array), len(array[0]) 
    offset = (0,-1,1) # 0 first so the current cell is the first in the gen 
    indices = ((i,j) for i in range(nn) for j in range(mm)) 
    for i,j in indices: 
     all_neigh = ((i+x,j+y) for x in offset for y in offset) 
     valid = ((i,j) for i,j in all_neigh if (0<=i<nn) and (0<=j<mm)) # -1 is a valid index in normal lists, but not here so throw it out 
     yield valid.next(), valid ## first is the current cell, next are the neightbors 

for (x,y), neigh in neighboring(l): 
    print l[x][y], [l[x][y] for x,y in neigh] 
0

może jesteś sprawdzając skrzynkę sudoku. Jeśli pole jest nxn i bieżąca komórka jest (x, y) rozpocząć sprawdzanie:

startingRow = x/n * n; 
startingCol = y/ n * n 
8

mb ...

from itertools import product, starmap 

x, y = (8, 13) 
cells = starmap(lambda a,b: (x+a, y+b), product((0,-1,+1), (0,-1,+1))) 

// [(8, 12), (8, 14), (7, 13), (7, 12), (7, 14), (9, 13), (9, 12), (9, 14)] 
print(list(cells)[1:]) 
+1

Nie rozumiem tej odpowiedzi i przeprowadziłem ją wraz z przykładem pytania w Pythonie 2.7. – octopusgrabbus

5

Zakładając, że macierz kwadratowa:

from itertools import product 

size = 3 

def neighbours(cell): 
    for c in product(*(range(n-1, n+2) for n in cell)): 
     if c != cell and all(0 <= n < size for n in c): 
      yield c 

Korzystanie itertools.product i dzięki Pythona yield expression i star operator funkcja jest dość dry ale wciąż wystarczająco czytelny.

Biorąc pod uwagę wielkość matrycę 3, można następnie (jeśli to konieczne) zebrać sąsiadów w list:

>>> list(neighbours((2,2))) 
[(1, 1), (1, 2), (2, 1)] 

Co funkcja nie może być wizualizowane w następujący sposób:

Function visualization

0

Jeśli ktoś jest ciekawy alternatywnego sposobu wybierania bezpośrednich (nie po przekątnej) sąsiadów, oto:

neighbors = [(x+a[0], y+a[1]) for a in 
        [(-1,0), (1,0), (0,-1), (0,1)] 
        if ((0 <= x+a[0] < w) and (0 <= y+a[1] < h))] 
Powiązane problemy