Decoding a telephone number that was masked with letters from the respective keys with APL Legend says phones used to have keyscitation needed and in those times, a person could "encode" a phone number by creating a word from the letters in the keys with the given numbers.

Below is the usual layout of the keys (that matter for my question) of a phone:

     | abc | def |
  1  |  2  |  3  |
------------------
 ghi | jkl | mno |
  4  |  5  |  6  |
------------------
pqrs | tuv | wxyz|
  7  |  8  |  9  |
------------------


I have to write a function that, given a vector of characters with uppercase letters/digits, recovers the original phone number.

For example,

'HELLO' -&gt; 4 3 5 5 6
'IAMYY4U' -&gt; 4 2 6 9 9 4 8
'' -&gt; ⍬


This is the code I have written:

Telephone ← {
  ⍝ Monadic function taking an uppercase string as input.
  ⍝ Decodes the number expressed with uppercase letters,
  ⍝ e.g. '1ABCZ' gives '12229'

  ⍝ Split letters and digits according to their keys (each digit goes to itself)
  keyStarts ← 'ADGJMPTW'
  splits ← ⎕D, keyStarts
  classes ← (1 -⍨ ⍳10), 1 + ⍳8

  classes[splits ⍸ ⍵]
}


I am particularly interested in a better way to create the classes variable, that looks like this 0 1 2 3 4 5 6 7 8 9 2 3 4 5 6 7 8 9 and this ordering depends obviously on the order of splits.

This comes from a problem from an APL competition.
I am particularly interested in a better way to create the classes variable, [...] this ordering depends obviously on the order of splits.


Because ASCII codes of A..Z come later than those of 0..9, we can't shorten the classes array itself. Instead, we can lengthen it, so that classes becomes simply two copies of 0..9. You can create unused intervals by copying the boundary item that comes after them:

    'BBB' ⍸ 'ABCD'
0 3 3 3


Incorporating it in Telephone:

  splits ← ⎕D, 'AAADGJMPTW'
  classes ← ,⍨ 1 -⍨ ⍳10




Nitpicking: When I need to subtract 1 from an expression, I use ¯1+expr instead of 1-⍨expr because the former reads better to me. This is a personal choice though. Or, if the "subtract 1" appears only for generating 0..n-1 instead of 1..n with ⍳, consider using ⎕IO←0.



Now, splits is creating the interval indices 0..20, and except the first 0, each index is mapped to 0..9,0..9.

interval index: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
class         : 0 1 2 3 4 5 6 7 8 9  0  1  2  3  4  5  6  7  8  9


Do you see the pattern? If you discard the unused interval and take modulo 10, you get the right class! Then you can entirely discard the variable classes and extra indexing:

Telephone ← {
  splits ← 1↓ ⎕D, 'AAADGJMPTW'
  10| splits ⍸ ⍵
}