23

我目前正在学习迷人的 J 编程语言,但我无法弄清楚的一件事是如何过滤列表。

假设我有任意列表3 2 2 7 7 2 9,我想删除 2s 但保持其他所有内容不变,即我的结果将是3 7 7 9. 我到底该怎么做?

4

4 回答 4

38

简短的回答

   2 (~: # ]) 3 2 2 7 7 2 9
3 7 7 9


长答案

我有你的答案,但在你应该熟悉一些细节之前。开始了。

单子,二元

J中有两种动词: monadsdyads。前者只接受一个参数,后者接受两个参数。

例如,将一个唯一参数传递给一个名为tally的单子动词,它会计算列表中元素的数量:#

   # 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

( ~:not equal) 在此示例中是二元的,并产生一个布尔值列表,当参数不等于时为真2。这是F根据图表的应用程序。

下一个应用是H

   2 ] 3 2 2 7 7 2 9
3 2 2 7 7 2 9

]( identity ) 可以是monaddyad,但它总是返回传递给动词的右参数(有一个相反的动词,[它返回..是的,左参数!:)

到目前为止,一切都很好。FH在应用程序相应地返回这些值之后:

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

我们刚刚从2s 中过滤掉了列表。

参考

这两个文档中描述了略有不同的forkhook和其他原语(包括上面提到的):

其他有用的信息来源是Jsoftware 站点及其wiki和 Internet 上的一些邮件列表存档。

于 2010-05-19T13:01:11.640 回答
9

为了确保清楚,直接的方法 - 回答原始问题 - 是这样的:

   3 2 2 7 7 2 9 -. 2

这返回

3 7 7 9

更复杂的方法 - 生成布尔值并使用它来压缩向量 - 更加 APLish。

要在很长的帖子中回答另一个问题,返回第一个元素和它出现的次数,就是这样:

      ({. , {. +/ .= ]) 1 4 1 4 2 1 3 5
1 3

这是一个使用“{”的分叉。要获得第一项,“{. +/ . = ]”将第一项等于每个元素的次数相加,“,”作为连接这两个部分的中间动词。

于 2011-10-13T20:51:50.610 回答
5

还:

   2 ( -. ~ ]) 3 2 2 7 7 2 9
3 7 7 9
于 2010-10-19T18:17:50.973 回答
2

有一百万种方法可以做到这一点 - 模糊地困扰着我,这些事情并没有严格地从右到左进行评估,我是一个老 APL 程序员,我认为事情是从右到左的,即使它们不是.

如果这是我要放入一个程序中的东西,我想提取一些数字并且这个数字是一个常数,我会做以下事情:

(#~ 2&~:)  1 3 2 4 2 5
1 3 4 5 

我认为这是一种钩子之类的东西。表达式的右半部分生成不为 2 的真值向量,然后将左边的八叉戟交换其参数,使得真值向量是要复制的左参数,向量是右参数。我不确定钩子比带有参数副本的叉子快还是慢。

  +/3<+/"1(=2&{"1)/:~S:_1{;/5 6$1+i.6

156

上面的这个程序回答了这个问题,“对于 Yatzee 骰子的所有可能组合,有多少个骰子有 4 或 5 个匹配的数字?” 它在盒子中生成所有排列,单独对每个盒子进行排序,将它们拆箱作为副作用,并提取第 2 列,将盒子与它们自己的第 2 列进行比较,这是我曾经设法编写的唯一成功的分叉或钩子。理论是,如果有一个数字出现在 5、3 或更多次的列表中,如果对列表进行排序,中间的数字将是出现频率最高的数字。我尝试了许多其他的钩子和/或叉子,但每个都失败了,因为有些东西我只是没有得到。无论如何,真值表被简化为一个向量,现在我们确切地知道每组 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 只要我只有动词序列和选择,我就没有问题。当我开始不得不在动词中重复我的论点,以至于我不得不使用叉子和钩子时,我开始迷路了。

例如,这是我无法工作的事情。

((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,一旦它打破和失败并且零出现。

我认为然后我可以添加另一组括号,再次从列表中获取前导元素,并以某种方式记录这些数字,最终的想法是有另一个阶段,我将向量的逆应用于原始列表,并且然后使用 $: 返回相同动词的递归应用。有点像快速排序的例子,我想我有点理解,但我想我不明白。

但我什至无法靠近。我将把它作为一个单独的问题提出,以便人们得到适当的回答。

于 2011-09-15T21:08:07.660 回答