1

The following employee matrix of names and email addresses makes it visually clear that bob's email address is bob@example.com.

┌───────┬─────────────────────┐
│alice  │alice@example.com    │
├───────┼─────────────────────┤
│bob    │bob@example.com      │
├───────┼─────────────────────┤
│charlie│charlie47@example.com│
└───────┴─────────────────────┘

But how do I programmatically access the email address based on a given value in column 1? The best approach I've found so far is

(⊂'bob') {(⍵[;1]⍳⍺) 2 ⌷⍵} employees

This works, but is pretty verbose—I feel like I must be missing a much simpler way to do something that I would imagine to be fairly common.

Any tips on what I'm missing?

codesections
  • 8,900
  • 16
  • 50

2 Answers2

3

There are various ways your function could be formulated, but they are all along those tracks:

(⊂'bob'){(⍺⍳⍨⊣/⍵)⌷⊢/⍵}employee

However, using a function may be too much abstraction, since you may want to use the index to extract from a different table;

employee[employee[;1]⍳⊂'bob';2]

For ease of readability, you can name your columns:

(name email)←⍳2
employee[employee[;name]⍳⊂'bob';email]

But the classic way is actually to use a separate array for each column:

(name email)←↓⍉employee
email⌷⍨name⍳⊂'bob'

For more organisation (avoiding polluting the workspace with one name per column) you can collect them in a namespace:

(Employee←⎕NS⍬).(name email)←↓⍉employee
Employee.(email⌷⍨name⍳⊂)'bob'

If you want the best database performance, you should designate each column a fixed field-width:

(name email)←10 30(⊢↑⍨⊢∘≢,⊣)¨↑¨↓⍉employee
email⌷⍨name⍳10↑'bob'

Of course, you can put these into a namespace, but you can also store the columns as elements of a vector. This is called an inverted table.

employeeIT←10 30(⊢↑⍨⊢∘≢,⊣)¨↑¨↓⍉employee
(name email)←⍳2
(email⊃employeeIT)⌷⍨(names⊃employeeIT)⍳10↑'bob'

Another way to achieve high performance is to bind the name list with which causes APL to generate a hash table. In fact, you can bind the email list with indexing too and go for a completely functional approach:

(name email)←↓⍉employee
Name←name∘⍳
Email←⌷∘email
Email Name ⊂'bob'
Adám
  • 6,573
  • 20
  • 37
  • All very informative, thanks! That last approach is particularly nifty; extrapolating a bit from that makes me realize that I can arbitrarily treat any matrix as a hash table. Given a matrix with named columns, I can write `⌷∘name1 (name2∘⍳) target` and arbitrarily treat `name2` as a key for the hashtable. Wow! (Of course, that only works well if `name2` is unique, but it's still far better than a language where hashmaps have only one fixed key) – codesections Oct 06 '19 at 16:57
0

This seems more long...

  A←3 2⍴('Alice')('ralice@1')('bob')('abob@2')('charlie')('gchiarli@3')
  A
Alice   ralice@1   
bob     abob@2     
charlie gchiarli@3 
  q←{C←⍺⋄0=+/D←{C≡⍵}¨↑¨B←{{w[⍵;]}¨⍳≢w←⍵}⍵:⍬⋄↑1↓↑D/B}
  ⎕fmt ('charlie') q A
┌10─────────┐
│ gchiarli@3│
└───────────┘
  ⎕fmt ('') q A
┌0─┐
│ 0│
└~─┘
  ⎕fmt ('1') q A
┌0─┐
│ 0│
└~─┘
  ⎕fmt (1) q A
┌0─┐
│ 0│
└~─┘
  ⎕fmt 1 q A
┌0─┐
│ 0│
└~─┘
  ⎕fmt 'bob' q A
┌6──────┐
│ abob@2│
└───────┘
RosLuP
  • 153
  • 7