We all know 3 7 4[1] is 3 and 3 7 4[2] is 7, but what about 3 7 4[1.5]?
This article proposes an extension to indices in the APL family of languages, known as float indexing, which allows indexing an array X in its n-th dimension with any value in the (closed) interval ⎕io to ⎕io+n⌷⍴X, not just integers.
If X is a vector, the extension is quite trivial: define X[a] to be X[⌊a]X[⌈a]1|a. For higher-rank arrays, this requires some more thought.
Consider X to be the matrix 2 2⍴3 9 4 1, and a the vector 1.5 1.5. Let's draw a picture:
3 9
\ /
a
/ \
4 1
It really looks like X[a] should be an average of 3, 9, 4 and 1, that is, 4.25. In general, X[a] will be some function of the subarray delimited by the entries X[⌊a] and X[⌈a]. We can calculate the coefficients for one particular value by looking at how close the value is to the desired index.
I wrote the following (intentionally ugly) function for float indexing:
∆I←{
bitstrings←(⊂⍴∘2)(,⊤)¨⎕io-⍨∘⍳2∘*
X←⍵
coefficients←×⌿{1∘-@(⍸⍵)⊢1|,⍺}
index←{X⌷⍨⌊@(⍸⍵)⌈@(⍸~⍵)⊢,⍺}
+⌿⍺∘(index×coefficients)¨bitstrings≢⍺
}
Surely someone will contact me(1) and propose a four glyphs long reimplementation that actually makes use of array-oriented principles and/or obscure Dyalog behavior.
Should other index-related functions be changed as well? Of course. 3 7 4⍳5 should return either ⎕io+÷2 or ⎕io+5÷3 (or maybe both?).
Edit 2023-09-22: I came up with ⊣(1⊥,⍤⊢×(×⌿¨⍤1∘|⍤|⊂⍤⊣-¨~⍤,⍤⍳⍤⍴⍤⊢))(2↑⌊⍤⊣↓⊢) which I think is equivalent if ⎕io←0. You tell me which is better :)
Footnotes
-
If you actually want to contact me, ping @RubenVerg at The APL Orchard.