假设我有两个列表,一个是文本t
,一个是字符列表c
。我想计算每个字符出现在文本中的次数。
使用以下APL代码可以轻松完成此操作。
+⌿t∘.=c
然而它很慢。它取外部产品,然后对每一列求和。
这是一种O(nm)算法,其中n和m是t
和c
的大小。
当然,我可以在APL中编写一个逐字符读t
的程序程序,并在O(n + m)中解决这个问题(假设完美哈希)。
有没有办法在没有循环(或条件)的APL中更快地完成这项工作?我也接受J的解决方案。
修改 实际上,我这样做的地方是文本比字符列表短得多(字符是非ascii)。我正在考虑文本的长度为20,字符列表的长度为数千。
如果n小于m ,则有一个简单的优化。
w ← (∪t)∩c
f ← +⌿t∘.=w
r ← (⍴c)⍴0
r[c⍳w] ← f
r
w只包含t中的字符,因此表大小仅取决于t而不取决于c。该算法在O(n ^ 2 + m log m)下运行。其中m log m是进行交叉运算的时间。
但是,如果某人提供了大量的文本文件,仍然会优先使用子二次算法。
答案 0 :(得分:8)
NB。使用“key”(/。)副词w / tally(#)动词计数
#/.~ 'abdaaa'
4 1 1
NB。计算的项目是字符串的结尾。
~. 'abdaaa'
abd
NB。所以,如果我们计算目标和字符串
#/.~ 'abc','abdaaa'
5 2 1 1
NB。我们为每个目标项目额外获得一个。
countKey2=: 4 : '<:(#x){.#/.~ x,y'
NB。这从xs的每个计数中减去1(&lt; :)。
6!:2 '''1'' countKey2 10000000$''1234567890'''
0.0451088
6!:2 '''1'' countKey2 1e7$''1234567890'''
0.0441849
6!:2 '''1'' countKey2 1e8$''1234567890'''
0.466857
NB。隐性版
countKey=. [: <: ([: # [) {. [: #/.~ ,
NB。起初看起来要快一点
6!:2 '''1'' countKey 1e8$''1234567890'''
0.432938
NB。但重复时间10次表明它们是相同的。
(10) 6!:2 '''1'' countKey 1e8$''1234567890'''
0.43914
(10) 6!:2 '''1'' countKey2 1e8$''1234567890'''
0.43964
答案 1 :(得分:5)
我认为这个用J编写的例子符合你的要求。字符列表比文本长(但为了方便起见,两者都保持简短。)我没有检查时间,但我的直觉是它会很快。仅仅参考文本中实际出现的字符进行计数,只查看长字符集以关联文本中出现的字符。
c=: 80{.43}.a.
t=: 'some {text} to examine'
RawIndicies=: c i. ~.t
Mask=: RawIndicies ~: #c
Indicies=: Mask # RawIndicies
Tallies=: Mask # #/.~ t
Result=: Tallies Indicies} (#c)$0
4 20 $ Result
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 4 0
0 0 1 0 0 0 2 1 2 0 0 0 1 3 0 0 0 2 0 0
4 20 $ c
+,-./0123456789:;<=>
?@ABCDEFGHIJKLMNOPQR
STUVWXYZ[\]^_`abcdef
ghijklmnopqrstuvwxyz
答案 2 :(得分:4)
Dyalog v14引入了关键操作符(⌸
):
{⍺,⍴⍵}⌸'abcracadabra'
a 5
b 2
c 2
r 2
d 1
操作数函数将⍺
的字母和该字母(索引的矢量)的出现设为⍵
。
答案 3 :(得分:0)
count =: (i.~~.) ({,&0) (]+/"1@:=)
用法:
'abc' count 'abdaaa'
4 1 0
不确定它是如何在内部实现的,但这里是不同输入大小的时间:
6!:2 '''abcdefg'' count 100000$''abdaaaerbfqeiurbouebjkvwek''' NB: run time for #t = 100000
0.00803909
6!:2 '''abcdefg'' count 1000000$''abdaaaerbfqeiurbouebjkvwek'''
0.0845451
6!:2 '''abcdefg'' count 10000000$''abdaaaerbfqeiurbouebjkvwek''' NB: and for #t = 10^7
0.862423
我们不会在'自我分类'之前过滤输入日期,所以:
6!:2 '''1'' count 10000000$''1'''
0.244975
6!:2 '''1'' count 10000000$''1234567890'''
0.673034
6!:2 '''1234567890'' count 10000000$''1234567890'''
0.673864
答案 4 :(得分:0)
我在APL中的实施(NARS2000):
(∪w),[0.5]∪⍦w←t∩c
示例:
c←'abcdefg'
t←'abdaaaerbfqeiurbouebjkvwek'
(∪w),[0.5]∪⍦w←t∩c
a b d e f
4 4 1 4 1
注意:仅显示t中存在的那些字符
答案 5 :(得分:0)
如其他答案中所述,关键操作员直接执行此操作。然而,解决这个问题的经典APL方法仍然值得了解。
经典的解决方案是&#34;排序,转换和比较&#34;:
c←'missippi'
t←'abcdefghijklmnopqrstuvwxyz'
g←⍋c
g
1 4 7 0 5 6 2 3
s←c[g]
s
iiimppss
b←s≠¯1⌽s
b
1 0 0 1 1 0 1 0
n←b/⍳⍴b
n
0 3 4 6
k←(1↓n,⍴b)-n
k
3 1 2 2
u←b/s
u
imps
最后的答案:
z←(⍴t)⍴0
z
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
z[t⍳u]←k
z
0 0 0 0 0 0 0 0 3 0 0 0 1 0 0 2 0 0 2 0 0 0 0 0 0 0
此代码不在我的头顶,尚未准备好投入生产。必须寻找空案例 - 布尔移位可能不适合所有情况....
答案 6 :(得分:0)
我最初的想法是 Find 运算符的情况:
T←'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
C←'MISSISSIPPI'
X←+/¨T⍷¨⊂C
使用的字符是:
(×X)/T
IMPS
他们各自的频率是:
X~0
4 1 2 4
我只运行玩具箱,所以我不知道它的性能是什么,但我的直觉告诉我外层产品应该更便宜。 有什么想法吗?