从基于值的矩阵到 select 的惯用方式

Idiomatic way to select from a matrix based on value

下面的 employee 姓名和电子邮件地址矩阵从视觉上清楚地表明 bob 的电子邮件地址是 bob@example.com

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

但是我如何根据第 1 列中的给定值以编程方式访问电子邮件地址?迄今为止我发现的最佳方法是

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

这个 有效 ,但是非常冗长——我觉得我一定是错过了一种更简单的方法来做一些我认为很常见的事情。

有什么关于我遗漏的提示吗?

可以通过多种方式来制定您的函数,但它们都遵循这些轨道:

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

但是,使用函数可能过于抽象,因为您可能希望使用索引从不同的地方提取 table;

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

为了便于阅读,您可以将列命名为:

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

但经典的方法实际上是为每一列使用一个单独的数组:

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

为了更多的组织(避免每列一个名字污染工作区),您可以将它们收集在一个命名空间中:

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

如果你想要最好的数据库性能,你应该为每一列指定一个固定的字段宽度:

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

当然,您可以将它们放入命名空间,但您也可以将列存储为向量的元素。这称为 反转 table.

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

另一种实现高性能的方法是将名称列表与 绑定,这会导致 APL 生成散列 table。事实上,您也可以将电子邮件列表与索引绑定起来,并寻求一种完全实用的方法:

(name email)←↓⍉employee
Name←name∘⍳
Email←⌷∘email
Email Name ⊂'bob'

这个好像比较长...

  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│
└───────┘