Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

apply a verb to a sub-array, in place?

Tags:

j

In J, I can update a subset of an array in place according to some predicate, like so:

    y (k}~) |. y {~ k =. I. '123' e.~ y =. '[1.2.3]'
[3.2.1]

I realize I can factor out a conjunction here, but is there a more elegant way to do it in the first place? The 123 is just an example. What I want to do, specificially, is:

  • obtain an array of indices into an array (k)
  • extract the items of the array at those indices into a new array
  • transform that array into a new array with the same type and shape
  • put the values of the new array back into the slots.

Also, it's important that the verb operates on the array as a whole, because what I mainly want to do is permute and transform sub-arrays in place. (Hence the |. in the example.)

Is there a simpler way to do this?

like image 296
tangentstorm Avatar asked May 22 '14 22:05

tangentstorm


2 Answers

There's a more-or-less standard adverb for this:

   tweak  =: (@:{) (`[) (`]) }
   twist  =: |. tweak
   '123' (I.@:e.~ twist ]) '[1.2.3]'
[3.2.1]

Here, tweak uses the gerundial form of } to:

  1. Select the indices x from the array y using { .
  2. Apply a transformation function to that [sub-]array, using the bonded conjunction @{ . That is, the { selects, and the @: asks for a verb to apply to that selection; twist supplies this verb in the form of |. (reverse).
  3. Stuffs the transformed [sub]-array back into the original array y (indicated by ]) at the same indices x (indicated by [).

I'll note a couple things:

  1. Sub-array modification is fairly rare in J, as the language encourages holistic transformations. Put another way: items of an array are typically considered to be peers and are (normally) treated equally. Treating some items (indices) specially is unusual and requires greater care, particularly if the selection is ad-hoc (as opposed to regular, or following some pattern).
  2. "In place modification" is a misleading term, because (as you rightly indicate), a new array is built, and it is this new array which is modified. True in-place amendment is possible, but requires a different approach (involving name management and/or explicit code).
  3. There some cognitive dissonance in the particular example you selected: your lookup function, e., is intrinsically unordered, yet your transformation function, |., concerns itself solely with order. There's nothing wrong with that, per se, but it might be confusing in the context of reordering parts of an array (consider, e.g., y=.'[1.1.1]').
like image 181
Dan Bron Avatar answered Nov 08 '22 23:11

Dan Bron


Amend does exactly that. If I'm reading your question right, the following is a simpler way:

v1 =: [: I. e.~        NB. indeces
v0 =: [: |. e.~ # ]   NB. transform the subarray
v2 =: ]

'123' (v0`v1`v2) } '[1.2.3]'
[3.2.1]
like image 35
Eelvex Avatar answered Nov 08 '22 23:11

Eelvex