我目前正在学习迷人的J编程语言,但有一点我无法弄清楚如何过滤列表。
假设我有任意列表3 2 2 7 7 2 9
,我想删除2,但保持其他所有内容不变,即我的结果为3 7 7 9
。我该怎么做呢?
答案 0 :(得分:31)
2 (~: # ]) 3 2 2 7 7 2 9
3 7 7 9
我有答案,但在你熟悉一些细节之前。我们走了。
J中有两种类型的动词: monads 和 dyads 。前者只接受一个参数,后者接受两个参数。
例如,将唯一参数传递给名为 tally 的 monadic 动词#
,计算列表中元素的数量:
# 3 2 2 7 7 2 9
7
动词#
接受两个参数(左和右),称为 copy ,它是二元,用于复制元素右列表由左侧列表中的相应元素指定的次数(列表中可能还有唯一的元素):
0 0 0 3 0 0 0 # 3 2 2 7 7 2 9
7 7 7
J中有一个 fork 的概念,它是一系列3个动词,应用于它们的参数,可以是二元或一元的。
这是我在第一个片段中使用的一种 fork 的图表:
x (F G H) y
G
/ \
F H
/ \ / \
x y x y
它描述了动词应用于其参数的顺序。因此,这些应用程序发生:
2 ~: 3 2 2 7 7 2 9
1 0 0 1 1 0 1
此示例中的~:
(不等于)是二元,并产生一个布尔值列表,当参数不等于2
时,这些值为true。根据图表,这是F
应用程序。
下一个申请是H
:
2 ] 3 2 2 7 7 2 9
3 2 2 7 7 2 9
]
( identity )可以是 monad 或 dyad ,但它始终返回传递给a的正确参数动词(有一个相反的动词,[
返回..是的,左边的参数!:)
到目前为止,这么好。应用程序后F
和H
相应地返回这些值:
1 0 0 1 1 0 1
3 2 2 7 7 2 9
唯一要执行的步骤是G
动词应用程序。
正如我前面提到的,动词#
,它是二元(接受两个参数),允许我们从右边的参数复制项目的次数,分别是相应的左参数中的位置。因此:
1 0 0 1 1 0 1 # 3 2 2 7 7 2 9
3 7 7 9
我们刚刚从2
s过滤了列表。
这两个文件中描述了稍微不同的 fork , hook 和其他原始文件(包括上述文章):
其他有用的信息来源是Jsoftware site和their wiki以及互联网中的一些邮件列表档案。
答案 1 :(得分:6)
为了确保清楚,回答原始问题的直接方式是:
3 2 2 7 7 2 9 -. 2
返回
3 7 7 9
更精细的方法 - 生成布尔值并使用它来压缩矢量 - 更加简洁。
要在非常长的帖子中回答另一个问题,要返回第一个元素及其发生的次数,只需这样:
({. , {. +/ .= ]) 1 4 1 4 2 1 3 5
1 3
这是一个使用“{。”的分叉。获得第一项,“{。+ /。=]”以将第一项等于每个元素的次数加起来,并将“,”作为连接这两部分的中间动词。
答案 2 :(得分:4)
另外:
2 ( -. ~ ]) 3 2 2 7 7 2 9
3 7 7 9
答案 3 :(得分:1)
有一百万种方法可以做到这一点 - 模糊地说,让我困扰的是,这些事情并没有严格地从右到左评估,我是一个老的APL程序员,我认为即使他们这些东西也是合适的不是
如果我打算将某个程序放入一个程序中,我想提取一些数字并且数字是常数,我会做以下事情:
(#~ 2&~:) 1 3 2 4 2 5
1 3 4 5
我认为这是一种钩子。表达式的右半部分生成的真值向量不是2,然后左边的octothorpe交换了参数,因此真值向量是要复制的左参数,向量是正确的参数。我不确定钩子比带有参数副本的fork更快还是更慢。
+/3<+/"1(=2&{"1)/:~S:_1{;/5 6$1+i.6
156
上述程序回答了一个问题,“对于Yatzee骰子的所有可能组合,一个卷中有多少个有4个或5个匹配数字?”它生成所有排列,在框中,单独对每个框进行排序,将它们作为副作用取消装箱,并提取第2列,将框与它们自己的第2列进行比较,在我曾经设法编写的唯一成功的fork或hook中。理论上说,如果列表中出现的数字为5次,3次或更多次,如果对列表进行排序,则中间数字将是出现频率最高的数字。我尝试过其他一些钩子和/或叉子,每一个都失败了,因为有些东西我没有得到。无论如何,真值表被简化为一个向量,现在我们确切地知道每组5个骰子与中位数相匹配的次数。最后,将该数字与3进行比较,并计算成功比较的数量(大于3,即4或5)。
该程序回答了这样的问题,“对于从符号1到5中重复出现的所有可能的8位数字,有多少可以被4整除?”
我知道你只需要确定前25个中有多少可以被4整除并且相乘,但程序会或多或少立即运行。有一次,我有一个更复杂的程序版本,它生成了基数为5的数字,以便各个数字在0到4之间,为这样生成的数字加1,然后将它们放入基数10。这就像是1+(8$5)#:i.5^8
+ / 0 = 4 |,(8 $ 10)#。 &gt; {; / 8 5 $ 1 + i.5
78125
只要我有动词列车和选择,我就没有问题。当我开始不得不在动词中重复我的论点,以便我被迫使用叉子和钩子时,我开始迷路。
例如,这是我无法开展的工作。
((1&{~+/)*./\(=1&{))1 1 1 3 2 4 1
我总是得到索引错误。
要点是输出两个数字,一个与列表中的第一个数字相同,第二个数字与重复该数字的次数相同。
所以这很有效:
*./\(=1&{)1 1 1 3 2 4 1
1 1 1 0 0 0 0
我将第一个数字与列表的其余部分进行比较。然后我插入一个和压缩 - 这给了我一个1,只要我有一个完整的1的字符串,一旦它打破并失败并且零出现。
我认为我可以添加另一组parens,再次从列表中获取lead元素,并以某种方式记录这些数字,最终的想法是有另一个阶段,我将矢量的逆应用于原始列表,然后使用$:来获取相同动词的递归应用程序。有点像快速排序的例子,我认为我有点理解,但我想我没有。
但我甚至无法接近。我会将此问题作为一个单独的问题,以便人们获得适当的回答。