我目前正在学习引人入胜的J编程语言,但有一件事情我还没能弄清楚,那就是如何筛选列表。
假设我有一个任意的列表3 2 2 7 7 2 9
,我想要删除其中的2,但保留其他所有元素,即我的结果应该是3 7 7 9
。我该怎么做呢?
我目前正在学习引人入胜的J编程语言,但有一件事情我还没能弄清楚,那就是如何筛选列表。
假设我有一个任意的列表3 2 2 7 7 2 9
,我想要删除其中的2,但保留其他所有元素,即我的结果应该是3 7 7 9
。我该怎么做呢?
2 (~: # ]) 3 2 2 7 7 2 9
3 7 7 9
我可以给你答案,但在此之前你需要了解一些细节。我们开始吧。
J语言有两种类型的动词:单子和双子。前者只接受一个参数,后者接受两个参数。
例如,将参数传递给单子动词#
,也称为tally,会计算列表中元素的数量:
# 3 2 2 7 7 2 9
7
一个名为copy的dyadic动词(接受左和右两个参数), 用于将右侧列表中的元素根据左侧列表相应的元素指定的次数进行复制(列表中也可以只有一个元素):
0 0 0 3 0 0 0 # 3 2 2 7 7 2 9
7 7 7
J语言中有一个概念叫做“分叉”,它是将三个动词分别应用于它们的参数,可以使用二元或一元方式。
下面是我在第一个片段中使用的某种类型的分叉的图示:
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
时为真。根据图表,这是F
应用程序。H
: 2 ] 3 2 2 7 7 2 9
3 2 2 7 7 2 9
]
(identity) 可以是一个单子或双子,但它总是返回传递给动词的右参数(有一个相反的动词[
会返回...没错,就是左参数! :)
目前为止,一切正常。 应用后的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
的列表。
这两个文档描述了稍微不同类型的 fork、hook 和其他基本操作(包括上述内容):
其他有用的信息来源是 Jsoftware 网站 以及互联网上的一些邮件列表档案和维基。
为了确保清晰明了,回答原问题的直接方法如下:
3 2 2 7 7 2 9 -. 2
这将返回
3 7 7 9
({. , {. +/ .= ]) 1 4 1 4 2 1 3 5
1 3
2 ( -. ~ ]) 3 2 2 7 7 2 9
3 7 7 9
有许多方法可以做到这一点 - 它让我感到不安,模糊地感觉这些事情没有严格按从右到左的顺序进行评估,我是一个老APL程序员,即使它们不是从右到左,我也会把它们想象成从右到左。
如果我要将其放入程序中并想要提取某个常数数字,我会执行以下操作:
(#~ 2&~:) 1 3 2 4 2 5
1 3 4 5
我认为这是一种钩子排序。表达式的右半部分生成关于哪些不是2的真实向量,然后左边的井号交换其参数,以便真实向量成为复制的左参数,而向量成为右参数。我不确定使用钩子是否比带有参数副本的叉更快或更慢。
+/3<+/"1(=2&{"1)/:~S:_1{;/5 6$1+i.6
这个程序回答了一个问题:“对于所有可能的Yahtzee骰子组合,有多少在一次掷骰中有4或5个匹配数字?”它生成所有排列组合,将它们放入盒子中并分别排序每个盒子,作为副作用取消盒子,并提取第2列,将其与自己的第2列进行比较,在我成功编写的唯一一个fork或hook中。理论是,如果有一个数字在一个由5个数字组成的列表中出现了三次或更多次,如果你对列表进行排序,中间的数字将是出现频率最高的数字。我尝试过许多其他的钩子和/或叉子,但每一个都失败了,因为有些东西我就是不明白。无论如何,那个真值表被简化为一个向量,现在我们知道每组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)#。 > {;/8 5 $ 1 + i.5
78125
只要我只有动词训练和选择,我就没有问题。当我开始不得不在动词内重复我的参数,以至于我被迫使用forks和hooks时,我开始迷失方向。
例如,这里有一些我无法使其工作的东西。
((1&{~+/)*./\(=1&{))1 1 1 3 2 4 1
我总是遇到索引错误。
关键是要输出两个数字,一个与列表中的第一个数字相同,另一个与该数字重复的次数相同。
所以这部分是有效的:
*./\(=1&{)1 1 1 3 2 4 1
1 1 1 0 0 0 0
3 ((|=0:)#]) 1+i.1000
(使用两个强大的二元分叉符号),等等。非常有用! - Gregory Higley(#~ ~:&2)3 2 2 7 7 2 9
对我来说更容易一些。 - defhlt