确定单元二维列表的邻居

时间:2009-10-25 13:36:42

标签: python matrix

我有一个列表列表,比如

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

以图形方式表示为:

1 2 3
4 5 6
7 8 9

我正在寻找一种优雅的方法来检查单元格的邻居值,水平,垂直和对角线。例如,[0] [2]的邻居是[0] [1],[1] [1]和[1] [2]或者数字2,5,6。

现在我意识到我可以做一个暴力攻击检查每个值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]

但这很容易,我想通过看一些更优雅的方法我可以学到更多。

13 个答案:

答案 0 :(得分:18)

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

我不知道这是否被认为是干净的,但是这个单行通过迭代它们并丢弃任何边缘情况给你所有的邻居。

答案 1 :(得分:9)

... 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:])

答案 2 :(得分:6)

假设你有一个方阵:

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

使用itertools.product并感谢Python yield expressionstar operator,该功能非常dry但仍然可读。

如果矩阵大小为3,那么您可以(如果需要)收集list中的邻居:

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

该功能的功能可视化如下:

Function visualization

答案 3 :(得分:4)

for x_ in range(max(0,x-1),min(height,x+2)):
  for y_ in range(max(0,y-1),min(width,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(height,x+2)):
...   for y_ in range(max(0,y-1),min(width,y+2)):
...     if (x,y)==(x_,y_): continue
...     print a[x_][y_]
... 
2
5
6

答案 4 :(得分:2)

没有更清洁的方法来做到这一点。如果你真的想要你可以创建一个函数:

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

答案 5 :(得分:2)

如果有人对选择直接(非对角线)邻居的其他方式感到好奇,请转到:

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

答案 6 :(得分:1)

以下是您的清单:

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

因此(x,y)的水平邻居是(x +/- 1,y)。

垂直邻居是(x,y +/- 1)。

对角线邻居是(x +/- 1,y +/- 1)。

这些规则适用于无限矩阵。 为了确保邻域适合有限矩阵,如果初始(x,y)位于边缘,则只需对邻居的坐标应用一个限制 - 矩阵大小。

答案 7 :(得分: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]

我不知道你看起来有多优雅,但似乎没有任何硬编码。

答案 8 :(得分:0)

这会生成所有索引:

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]

答案 9 :(得分:0)

也许你正在检查一个数独盒子。如果框是n x n且当前单元格是(x,y),则开始检查:

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

答案 10 :(得分:0)

感谢@JS_is_bad对邻居的强烈暗示。这是此问题的运行代码

fileprivate func animateFireworks(scnPoint: CGPoint, color: UIColor) {
    // Set emitter properties
    let particleBirthRate = CGFloat(150)
    let maxParticles = 50
    let numEmitters = 5

    // SceneView point -> SpriteKit point
    let skOverlayPoint = skOverlay.convertPoint(fromView: scnPoint)

    // Create emitters
    for _ in 0..<numEmitters {
        let fireworksEmitter = SKEmitterNode(fileNamed: ExplosionEmitterFilename)!

        // Set particle size
        let particleSize = CGSize(width: 20, height: 20)
        fireworksEmitter.particleSize = particleSize

        // Set color for emitter
        fireworksEmitter.particleColorSequence = nil
        fireworksEmitter.particleColor = color

        // Set number of particles
        fireworksEmitter.particleBirthRate = particleBirthRate
        fireworksEmitter.numParticlesToEmit = maxParticles

        // Position at point
        fireworksEmitter.position = skOverlayPoint

        // Add to SpriteKit overlay
        skOverlay.addChild(fireworksEmitter)

        // Remove emitter, <animationDur> is only a rough estimate
        let animationDur = 3 * Double(fireworksEmitter.particleLifetime + fireworksEmitter.particleLifetimeRange)
        delay(animationDur) {
            fireworksEmitter.removeFromParent()
        }
    }
}


func delay(_ delay:Double, closure:@escaping ()->()) {
    DispatchQueue.main.asyncAfter(
        deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
}


> Thread 11 Queue : com.apple.scenekit.renderingQueue.SCNView0x121d8d570
> (serial)
> #0    0x000000019c710aac in SKCParticleManager::enumerateParticleSystems(void (SKCParticleSystem*)
> block_pointer) ()
> #1    0x000000019c723d74 in SKCParticleSystemNode::generateRenderData_Quads(SKCRenderInfo*) ()
> #2    0x000000019c7236c0 in SKCParticleSystemNode::addRenderOps_Quads(SKCRenderInfo*,
> std::__1::shared_ptr<jet_command_buffer> const&) ()
> #3    0x000000019c71dc4c in SKCRenderer::expandRenderGroup(std::__1::shared_ptr<SKCRenderSortGroup>
> const&, std::__1::shared_ptr<jet_command_buffer> const&) ()
> #4    0x000000019c71b238 in SKCRenderer::expandRenderPass(std::__1::shared_ptr<SKCRenderPass>
> const&, std::__1::shared_ptr<jet_command_buffer> const&) ()
> #5    0x000000019c71a888 in SKCRenderer::render(SKCNode*, float __vector(4), std::__1::shared_ptr<jet_framebuffer> const&, unsigned int __vector(4), simd_float4x4, bool, NSDictionary*, SKCStats*,
> SKCStats*, double) ()
> #6    0x000000019c6516a4 in -[SKSCNRenderer renderWithEncoder:pass:commandQueue:] ()
> #7    0x0000000199479fc8 in -[SCNRenderContextMetal renderSKSceneWithRenderer:overlay:atTime:] ()
> #8    0x0000000199525018 in -[SCNRenderer _drawOverlaySceneAtTime:] ()
> #9    0x00000001995e199c in __C3DEngineContextRenderPassInstance ()
> #10   0x00000001995e27cc in C3DEngineContextRenderMainTechnique ()
> #11   0x0000000199526508 in -[SCNRenderer _renderSceneWithEngineContext:sceneTime:] ()
> #12   0x0000000199526688 in -[SCNRenderer _drawSceneWithNewRenderer:] ()
> #13   0x0000000199526ccc in -[SCNRenderer _drawScene:] ()
> #14   0x0000000199527144 in -[SCNRenderer _drawAtTime:] ()
> #15   0x00000001995cfa74 in -[SCNView _drawAtTime:] ()
> #16   0x00000001994876c0 in __69-[NSObject(SCN_DisplayLinkExtensions) SCN_setupDisplayLinkWithQueue:]_block_invoke ()
> #17   0x000000019959700c in __36-[SCNDisplayLink _callbackWithTime:]_block_invoke ()
> #18   0x00000001042a12cc in _dispatch_call_block_and_release ()
> #19   0x00000001042a128c in _dispatch_client_callout ()
> #20   0x00000001042aff80 in _dispatch_queue_serial_drain ()
> #21   0x00000001042a47ec in _dispatch_queue_invoke ()
> #22   0x00000001042b0f6c in _dispatch_root_queue_drain_deferred_wlh ()
> #23   0x00000001042b8020 in _dispatch_workloop_worker_thread ()
> #24   0x00000001858a6f1c in _pthread_wqthread ()

答案 11 :(得分:0)

如果lambdas在这里嘲笑你。但是lambdas让你的代码看起来很干净。@ johniek_comp有一个非常干净的解决方案TBH

k,l=(2,3)
x = (0,-1,+1)
y = (0,-1,+1)
cell_u = ((k+a,l+b) for a in x for b in y)
print(list(cell_u))

答案 12 :(得分:0)

受到先前答案之一的启发。

您可以使用min()和max()函数来缩短计算时间:

width = 3
height = 3

[(x2, y2) for x2 in range(max(0, x-1), min(width, x+2)) 
                    for y2 in range(max(0, y-1), min(height, y+2))
                    if (x2, y2) != (x, y)]