10

Assume I have a $m\times n$ matrix and I would like to extract four neighbors of randomly selected entry of a matrix. I have handled if location is not on the boundary. Any suggestion how to handle it if entry is on the boundary or handle it all in once? Thanks.

Here is an example.

SeedRandom[123];
{n, m} = {4, 6};
mat = RandomInteger[{1, 5}, {n, m}];
MatrixForm@mat

$\text{mat}= \left( \begin{array}{cccccc} 4 & 2 & 3 & 1 & 1 & 3 \\ 4 & 2 & 2 & 5 & 1 & 2 \\ 5 & 4 & 3 & 3 & 5 & 5 \\ 3 & 5 & 2 & 2 & 5 & 3 \\ \end{array} \right)$

loc = {RandomInteger[{2, n - 1}], RandomInteger[{2, m - 1}]}
fourNeighbor = (Extract[mat, # + loc] &) /@ {{0, -1}, {0, 1}, {-1, 0}, {1, 0}}

Edit:

Here is Moore Neighbors

nf = Nearest[Tuples@Range@Dimensions@mat -> Flatten[mat], 
   DistanceFunction -> ChessboardDistance];

neighbors[pt_] := nf[pt, {All, 1}][[1 ;;]]

Or

   mooreNeighborPositions =  AdjacencyList[NearestNeighborGraph[Tuples@Range@Dimensions@#,
 DistanceFunction -> ChessboardDistance], #2] &;

mooreNeighbors = Extract[#, mooreNeighborPositions@##] &; mooreNeighbors[mat, {1, 1}]

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
OkkesDulgerci
  • 10,716
  • 1
  • 19
  • 38
  • 3
    How do you want to handle boundary cases? Wrap around (periodic) or include <4 neighbors or ? – Chris K Dec 21 '17 at 15:24

4 Answers4

10

You could use Nearest for this.

nf = Nearest[Tuples @ Range @ Dimensions @ mat -> Flatten[mat]];

neighbors[pt_] := nf[pt, {All, 1}][[2;;]]

Some examples:

neighbors[{3, 3}]
neighbors[{1, 1}]
neighbors[{4, 6}]

{2, 4, 3, 2}

{2, 4}

{5, 5}

Carl Woll
  • 130,679
  • 6
  • 243
  • 355
8
vNNeighborPositions = AdjacencyList[
   NearestNeighborGraph @ Tuples @ Range @ Dimensions @ #, #2] &;

vNNeighbors = Extract[#, vNNeighborPositions @ ##] &;

Examples:

Row[Labeled[Style[#, 20] & @ MatrixForm @
      MapAt[Highlighted[#, Background -> Red] &, 
       MapAt[Highlighted, mat, vNNeighborPositions[mat, #]], #], 
    Grid[{{"pos:", #}, {"neighbors:", vNNeighbors[mat, #]}}], Top] & /@ 
 {{1, 1}, {1, 4}, {3, 1}, {4, 6}, {3, 5}}, 
 Spacer[10]]

enter image description here

SeedRandom[333]
mat = RandomInteger[10, {10, 15}];
poslist = RandomSample[Tuples @ Range @ Dimensions @ mat, 7];

Legended[MatrixPlot[ReplacePart[mat, Join[Thread[poslist -> (ColorData[97] /@ Range[Length@poslist])], Thread[vNNeighborPositions[mat, #] & /@ poslist -> Yellow], {{_, _} :> White}]], ImageSize -> 1 -> 40, Mesh -> All, Epilog -> MapIndexed[Text[Style[#, 16, Black], #2 - .5] &, Reverse /@ Transpose @ mat, {2}]], Placed[SwatchLegend[(ColorData[97] /@ Range[Length @ poslist]), Style[#, 14] & /@ ({Defer @ #, vNNeighbors[mat, #]} & /@ poslist), LegendMarkerSize -> 20, LegendLabel -> "positions & neighbors"], Right]]

enter image description here

kglr
  • 394,356
  • 18
  • 477
  • 896
2

The four neighbors are

ij=Map[loc + # &, {{0, -1}, {0, 1}, {-1, 0}, {1, 0}}]

Now you must check the index range:

DeleteCases[Map[{Max[1,Min[n,#[[1]] ]],Max[1,Min[m,#[[2]] ]]}& ,ij],loc] (* index pairs*)
Extract[mat,%] (* neighbors  *)
Ulrich Neumann
  • 53,729
  • 2
  • 23
  • 55
1
nbrs[loc_?VectorQ, m_?MatrixQ] := Module[{nrows, ncols, pts},
  {nrows, ncols} = Dimensions[m];
  pts = Select[(loc + # &) /@ {{0, -1}, {0, 1}, {-1, 0}, {1, 0}},
    Between[#[[1]], {1, nrows}] && Between[#[[2]], {1, ncols}] &];
  Extract[mat, pts]
  ]
Alan
  • 13,686
  • 19
  • 38