2
\$\begingroup\$

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' -> 4 3 5 5 6
'IAMYY4U' -> 4 2 6 9 9 4 8
'' -> ⍬

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.

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

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 ⍸ ⍵
}
\$\endgroup\$
1
  • \$\begingroup\$ I like your "nitpicking" here about the ¯1 + .... I have adopted it in my code already. Also, really nice simplification of the code with the extended splits, thanks! \$\endgroup\$
    – RGS
    Apr 12, 2020 at 15:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.