APL中的Explode和Implode

3
如何使用APL实现类似于PHP中的explodeimplode函数?
我尝试自己解决并想了一个解决方案,下面是我的解决方法。我也想看看其他可能的解决方法。

如果您想让您的代码接受审查,程序员社区可能更适合,因为他们允许进行代码审查:http://programmers.stackexchange.com/ - 尽管在这里自问自答的问题也是有效的,所以我不会投票标记为离题。-- 参考资料(维基百科):APL(编程语言) - hakre
@hakre - 我并不是真的在寻求评论,但无论如何我都欢迎。 - Expedito
代码审查可以在http://codereview.stackexchange.com/上进行,而不是程序员论坛,虽然我认为在这里也可以。特别是由于APL社区非常小,在其他网站上很难被看到,更不用说得到答复了。 - Orbling
3个回答

3
Pé,APL中寻找“简短”和/或“优雅”的标准问题解决方案的探索早于PHP,甚至早于新术语,如“explode”,“implode”(我认为——但我必须承认我不知道这些术语有多老...)。无论如何,早期的APL程序员用“惯用法”一词来表示这种“标准问题的解决方案,适合在一行APL中完成”。
由于某种原因,芬兰人特别有创意,甚至开始制作这些列表,以便新手更容易上手。即使在做了20年APL后,我仍然发现这些内容很有用。它被称为“FinnAPL”——芬兰APL惯用法库,您可以在此处浏览:https://aplwiki.com/wiki/FinnAPL_idiom_library顺便说一句,整个APL Wiki可能会很有趣...
但是,您可能需要在措辞上有所创意,以找到解决方案;还有一个警告:FinnAPL仅适用于“经典”(非嵌套)数据结构(嵌套矩阵随着现在的标准“APL2”而来),因此他们处理数据的某些方式可能不再是“最先进”的(即在“旧时代”,CAT BIRD和DOG将被表示为一个3x4的数组,因此字符串数组的“implode”就像,array,delimeter一样简单(但您随后必须挑战删除用于填充的空格)。
无论如何,我不确定为什么会写这篇文章——只是一些想法,当我想起我的APL之旅时涌上心头;)
好的,让我也看一下问题。当您的分隔符是单个字符时,处理此类问题的APL2ish-惯用方式类似于:
⎕ml←3    ⍝ "migration-level" (only Dyalog APL) to ensure APL2-compatibility
s←' '
A←s,'BIRD',s,'CAT',s,'DOG'     ⍝ note that delimeter also used as 1st char!
exploded_string←1↓¨(+\A=s)⊂A   ⍝ explode
imploded←∊s,¨exploded_string
A≡imploded                     ⍝ test for successfull round-trip should return 1

我做这个练习是为了熟悉APL,这是一个很好的学习经验,尤其是现在我看到了惯用的解决方案。还要感谢提供Finn库的链接! - Expedito
1
我理解你的感受 - 你正在追求一次伟大的冒险!:-)可能每个APL程序员都有自己的工具箱来解决这些任务,而这些工具的改进可能是一生的旅程;-) - MBaas
这是一个不错的分割函数,尽管只能处理单个字符的分隔符,因为A=s部分会出现长度错误。但这种技术可以进行适应性调整。这种方法的一个有用之处在于它保留了两个分隔符相邻时的空分区。将A改为A←s,'BIRD',s,s,'CAT',s,'DOG',然后尝试0=⍴¨exploded_string以查看空集合。 - Orbling

2

分割字符串:

假设有以下文本字符串和分隔符字符串:

F←'CAT BIRD DOG'
B←' '

可以通过以下方式来实现explode:

S←⍴,B
P←(⊃~∨/(-S-⍳S)⌽¨S⍴⊂B⍷F)⊂F
P[2] ⍝ returns BIRD

限制:

PHP的explode函数在两个分隔符相邻时返回一个空数组值。上面的代码简单地忽略了这一点,并将两个分隔符视为一个。

上面的代码也没有处理重叠的分隔符。如果使用重复字符作为分隔符,则最有可能出现这种情况。例如:

F←'CATaaaBIRDaaDOG'
B←'aa'
S←⍴,B
P←(⊃~∨/(-S-⍳S)⌽¨S⍴⊂B⍷F)⊂F
P ⍝ returns CAT BIRD DOG

然而,预期的结果应该是CAT aBIRD DOG,因为它不认识'aaa'作为紧跟着'a'的分隔符。相反,它将其视为两个重叠的分隔符,最终起到单个分隔符的作用。另一个例子是'tat'作为分隔符,在这种情况下,字符串中出现的任何'tatat'都会有同样的问题。
重叠分隔符:
我提供了一种解决单个重叠可能性的替代方案:
S←⍴,B
A←B⍷F
A←(2×A)>⊃+/(-S-⍳S)⌽¨S⍴⊂A
P←(⊃~∨/(-S-⍳S)⌽¨S⍴⊂A)⊂F

第三行代码会消除在当前位置前距离任何定界符位置小于S-1个字符的所有字符串。如我所说,这只解决单个重叠的问题。如果有两个或更多的重叠,则第一个被识别为定界符,其余所有的都被忽略。下面是两个重叠的示例:

F←'CATtatatatBIRDtatDOG'
B←'tat'
S←⍴,B
A←B⍷F
A←(2×A)>⊃+/(-S-⍳S)⌽¨S⍴⊂A
P←(⊃~∨/(-S-⍳S)⌽¨S⍴⊂A)⊂F
P ⍝ returns CAT atatBIRD DOG

预期结果应该是'CAT a BIRD DOG',但由于重叠的原因无法将最后的'tat'识别为分隔符。除非使用重复字符,否则这种情况很少发生。如果分隔符是'aa',那么'aaaa'将被认为是双重重叠,并且只有第一个分隔符会被识别。
合并:
要简单得多:
P←'CAT' 'BIRD' 'DOG'
B←'-'
(⍴,B)↓∊B,¨P

它按预期返回“CAT-BIRD-DOG”。

这是一个很好的解决方案,我喜欢使用(-S-⍳S)和旋转来匹配整个分隔符。我认为这是一种标准技术,但仍然很好看。为了避免重叠,您可能需要使用未使用的字符对分隔符进行标记,然后在两个相邻的分隔符标记之间添加不同的标记来表示空集。 - Orbling
@Orbling - 感谢您的评论。我对APL还很陌生,所以不知道这是否是标准技术。那时候这是有意义的做法。 - Expedito

1

使用reduce函数可以实现一个有趣的替代implode的方法:

      p←'cat' 'bird' 'dog'
      ↑{⍺,'-',⍵}/p
cat-bird-dog

这种技术不需要明确引用定界符的形状。
而使用 n-wise reduction 可以得到一个有趣的 explode 替代方案:
      f←'CATtatBIRDtatDOG'
      b←'tat'
      b{(~(-⍴⍵)↑(⍴⍺)∨/⍺⍷⍵)⊂⍵}f
 CAT  BIRD  DOG 

1
谢谢你的回答。这里已经很晚了,所以我得明天仔细看一下。不过有一件事让我困惑,我正在使用不支持花括号的NARS2000,而且我也不熟悉花括号语法。明天我会努力解密它的。 - Expedito
花括号用于“动态函数”,这是一种供应商特定的扩展,由Dyalog发明。 (如果您有兴趣,还可以从Dyalog获得免费版本以供个人使用 - 您也可以在http://tryapl.org上尝试APL在线) - MBaas
我将你的explode代码分配给P,而P[3]的结果是“Ttat”,而不是预期的“DOG”。 - Expedito
@PédeLeão:很高兴看到有人也在使用NARS2000,这是我一直在用的。Dyalog很棒,但确实有很多专有扩展——这总是在问题和答案中引起麻烦,因为大多数人都认为你在使用Dyalog。 - Orbling
由于在explode上的二元动态函数实际上只是在执行⍵←f ⋄ ⍺←b,因此通过交换字母,它可以在任何其他地方运行:(~(-⍴f)↑(⍴b)∨/b⍷f)⊂f - Orbling
我喜欢这种方法,唯一的小问题是,如果分隔符出现在前⍴b个字符中,则由于take拉入零来补足前面的长度,它会搞乱删除初始分隔符。如果在take之前初始数字为1,则确保集合以⍴b个前缀为1开始,应该可以解决这个问题。 - Orbling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接