Re: Using Extract where some indices are out of bounds (efficiently)

*To*: mathgroup at smc.vnet.net*Subject*: [mg115219] Re: Using Extract where some indices are out of bounds (efficiently)*From*: Ray Koopman <koopman at sfu.ca>*Date*: Tue, 4 Jan 2011 04:28:24 -0500 (EST)*References*: <iev2kf$4mq$1@smc.vnet.net>

On Dec 23 2010, 12:52 am, Julian Francis <julian.w.fran... at gmail.com> wrote: > Dear all, > > How can I arrange to use Extract to extract values from an array; but > where some of the indices may be out of bounds, in which case they > should be simply ignored? > > I wrote a simple arrayInBounds function, and then did a Select on that > to retrieve only the indices which are in bounds, which are then fed > into Extract. Whilst this works it seems to lead to a 150* reduction > in speed. > > FYI: > My arrayInBounds function looks like this: > > arrayInBounds[array_, index_] := > If[index == {}, True, > First[index] > 0 && First[index] < Length[array] && > arrayInBounds[array[[1]], Rest[index]]] > > My support functions for the test are: > > disks = Table[ > Transpose[Position[DiskMatrix[r, 2*(r + 1) + 1], 1]], {r, 1, 30}]; > > positions[x_, y_, r_] := Transpose[{ > disks[[r, 1]] + y - (r + 2), > disks[[r, 2]] + x - (r + 2)}] > > My timing tests are: > > In[291]:= Timing[lists=Table[Extract[image,Select[positions[x,y, > 10],arrayInBounds[image,#]&]], > {y,11,64-11}, > {x,11,64-11}];] > Out[291]= {17.175,Null} > In[292]:= Timing[lists2=Table[Extract[image,positions[x,y,10]], > {y,11,64-11}, > {x,11,64-11}];] > Out[292]= {0.094,Null} > In[293]:= lists==lists2 > Out[293]= True > > image is assumed to be an array of at least 64*64. > > In this particular case, the bounds are setup so that the checking > serves no purpose and can be eliminated, but I've only done this to > show the speed comparison with the no bounds checking comparison. The > speed difference is a factor of over 150! This seems surprising to me. > Is there a better way? > > I don't think I can reformulate it using partitions, or the standard > imagefilter functions, because in general the functions positions will > be giving a complicated list of coordinates which doesn't naturally > fit into a square kernel. > > Any help greatly appreciated. > > Thanks, > Julian. Is this the sort of thing you're looking for? myExtract[array_,indices_] := With[{m = Dimensions@array}, Extract[ array, Select[indices, And@@Positive@# && And@@Thread[# <= m]&]]] a = Array[FromDigits@{##}&,{2,3,4}] {{{111,112,113,114},{121,122,123,124},{131,132,133,134}}, {{211,212,213,214},{221,222,223,224},{231,232,233,234}}} myExtract[a,{{0,1,2},{1,2,3},{2,3,4},{3,4,5}}] {123,234} myExtract[a[[2,2]],Transpose@{Range[0,5]}] {221,222,223,224}