Here's a simple solution using a single precomputed NearestNearestFunction
; much faster than $O(n^2)$. I've written it assuming the sites are in a list ps
, rather than embedded inside a function p
;, because I think this way is easier to generate and manipulate. You may want to modify the code as appropriate.
num = 5000;
ps = RandomInteger[{1, 100}, {num, 2}];
nf = Nearest[Table[ps[[i]] -> i, {i, Length[ps]}]] (* so it returns the index of the site *)
upToNthNearestSites[k_, 0] := {k} (* the "zeroth" nearest neighbour, i.e. itself *)
upToNthNearestSites[k_, n_] := Module[{pk, near, d},
pk = ps[[k]];
near = upToNthNearestSites[k, n - 1]; (* get the nearest neighbours up to order n-1 *)
near = nf[pk, Length[near] + 1]; (* get one more; this is one of the nth nearest *)
d = N@EuclideanDistance[pk, ps[[Last@near]]]; (* distance to the nth nearest *)
nf[pk, {Infinity, d}] (* the solution is all the sites up to that distance *)
]
nthNearestSites[k_, n_] := Module[{pk, near0, near, d},
pk = ps[[k]];
near0 = upToNthNearestSites[k, n - 1];
near = nf[pk, Length[near0] + 1];
d = N@EuclideanDistance[pk, ps[[Last@near]]];
near = nf[pk, {Infinity, d}];
Complement[near, near0] (* same as above except remove neighbours closer than n *)
]