以下内容应该适用于任何主流 APL 实现。
让我们从一个简单的字符向量开始:
m ← 3 7⍴'ABA455 7L9O36GDZLFPEI'
v ← m[1;]
v
ABA455
我们可以通过过滤来查找唯一字符,以仅保留与第一次出现的索引相同的元素:
v ⍳ v
1 2 1 4 5 5 7
⍳ ⍴ v
1 2 3 4 5 6 7
( v ⍳ v ) = ⍳ ⍴ v
1 1 0 1 1 0 1
⎕ ← unique ← ( (v ⍳ v) = ⍳ ⍴ v ) / v
AB45
现在我们将独特元素与每个元素进行比较:
unique ∘.= v
1 0 1 0 0 0 0
0 1 0 0 0 0 0
0 0 0 1 0 0 0
0 0 0 0 1 1 0
0 0 0 0 0 0 1
水平汇总此表即可得出每个唯一元素的出现次数:
+/ unique ∘.= v
2 1 1 2 1
现在我们只需要将唯一元素与其各自的计数配对:
unique ,[1.5] +/ unique ∘.= v
A 2
B 1
4 1
5 2
1
让我们将其放入效用函数中:
∇ c ← Counts v; u
u ← ( (v ⍳ v) = ⍳ ⍴ v ) / v
c ← u ,[1.5] +/ u ∘.= v
∇
Counts v
A 2
B 1
4 1
5 2
1
现在我们需要将此函数应用于矩阵的每一行。我们首先将矩阵分割成向量的向量:
⊂[2] m
┌───────┬───────┬───────┐
│ABA455 │7L9O36G│DZLFPEI│
└───────┴───────┴───────┘
然后我们将效用函数应用于每个向量:
Counts¨ ⊂[2] m
┌───┬───┬───┐
│A 2│7 1│D 1│
│B 1│L 1│Z 1│
│4 1│9 1│L 1│
│5 2│O 1│F 1│
│ 1│3 1│P 1│
│ │6 1│E 1│
│ │G 1│I 1│
└───┴───┴───┘
在线尝试一下! https://tio.run/##SyzI0U2pTMzJT///P1fhUdsEBWMF80e9W9QdnRxNTE0VzH0s/Y3N3F2ifNwCXD3VuR51tCskg9U555fmlRQrlFkrlHIpKJSCxTQUNMoe9W4u01SwVQDSQHPKFDQV9BXKgCogukoVdKIN9UxjFbT1QXo6ZujZAmWBpnI96puKZO6hFQqPupqijWIVcv//BwA
如果您使用的是 Dyalog APL,则密钥运算符 (⌸
)正是您所需要的:
{⍺ ⍵}⌸ 'ABA455'
┌─┬───┐
│A│1 3│
├─┼───┤
│B│2 │
├─┼───┤
│4│4 │
├─┼───┤
│5│5 6│
└─┴───┘
它采用单个操作数,并为每个唯一值调用一次,特定值作为左参数,出现索引列表作为右参数。然而,我们对实际发生的事件并不感兴趣,只对它们的计数感兴趣:
{⍺ (≢⍵)}⌸ 'ABA455'
A 2
B 1
4 1
5 2
现在我们只需在每一行上应用这个函数即可。我们可以通过分割矩阵并将函数应用于 Each 来做到这一点:
{⍺ (≢⍵)}⌸¨ ↓ m
┌───┬───┬───┐
│A 2│7 1│D 1│
│B 1│L 1│Z 1│
│4 1│9 1│L 1│
│5 2│O 1│F 1│
│ 1│3 1│P 1│
│ │6 1│E 1│
│ │G 1│I 1│
└───┴───┴───┘
在线尝试一下! https://tio.run/##SyzI0U2pTMzJT///P1fhUdsEBWMF80e9W9QdnRxNTE0VzH0s/Y3N3F2ifNwCXD3VuR71TQWrqn7Uu0tB41Hnoke9WzVrH/XsOLQCKD5ZIff/fwA