在 J 中 "chain" 的非尴尬方式?
A non-awkward way to "chain" in J?
这个问题经常出现,我总是发现自己在与它作斗争。所以我想要最终的解决方案,如果有的话。
根本问题归结为这个冲突:
- J 喜欢使用同类列表/tables 等(即没有包含不同长度项目的列表,例如)
- 有时您想将一个动词应用于列表的每个项目,其中动词的结果本身就是一个项目数量不同的列表。
这通常在函数式语言中使用 chain
(或 flat_map
)来解决。
演示一般问题的示例
举一个具体的例子,假设您想列出列表 0 1 2 3
中所有可能的对,其中第一个严格小于第二个:
0 1
0 2
0 3
1 2
1 3
2 3
当然,您可以 table ,/
或编目 {
以获得完整的叉积,然后进行过滤,这样您就只剩下上三角了:
即取,"0/~ i.4
的结果:
0 0
0 1
0 2
0 3
1 0
1 1
1 2
1 3
2 0
2 1
2 2
2 3
3 0
3 1
3 2
3 3
其实为了让几何更清晰,我们将其显示为;/"2 ,"0/~ i.4
:
┌───┬───┬───┬───┐
│0 0│0 1│0 2│0 3│
├───┼───┼───┼───┤
│1 0│1 1│1 2│1 3│
├───┼───┼───┼───┤
│2 0│2 1│2 2│2 3│
├───┼───┼───┼───┤
│3 0│3 1│3 2│3 3│
└───┴───┴───┴───┘
现在我们求的结果是三角形的上半部分。但是这种方法有缺点:
- 我们必须做双倍的工作。
- 我们必须引入一个单独的过滤步骤来删除我们不起作用的额外结果。
- 以上两件事掩盖了我们代码的意图。
使用 {
的解决方案有类似的问题。
如果……就好了
chain
方法看起来像这样:
g=. ,"0 i.
(g 0);(g 1);(g 2);(g"0 i.3);<(<@g"0 (1+i.3))
产生:
┌──┬───┬───┬───┬─────────────┐
│ │1 0│2 0│0 0│┌───┬───┬───┐│
│ │ │2 1│0 0││1 0│2 0│3 0││
│ │ │ │ ││ │2 1│3 1││
│ │ │ │1 0││ │ │3 2││
│ │ │ │0 0│└───┴───┴───┘│
│ │ │ │ │ │
│ │ │ │2 0│ │
│ │ │ │2 1│ │
└──┴───┴───┴───┴─────────────┘
最后两列接近我想要的,但在倒数第二列中,自动填充的麻烦掩盖了我们的结果,在最后一列中,我们正确的结果被装箱,但取消装箱 [=74= 】 补。
什么是解决此类问题的好方法(惯用 J)?
注意:我不是在寻找示例中问题的临时解决方案,而是chain
解决的一般问题的解决方案在其他语言中。
我认为这个答案对于你想要的来说太具体了,但它确实表明挑战的第 2 部分(可变长度结果)的解决方案是使用 each=:&.>
这样填充就可以了避免了。
(< 0 1 2 3) ;"1@:((],.>#[) each) 0 1 2 3
0 1
0 2
0 3
1 2
1 3
2 3
(< 0 1 2 3) ((],.>#[) each) 0 1 2 3
+---+---+---+--+
|0 1|1 2|2 3| |
|0 2|1 3| | |
|0 3| | | |
+---+---+---+--+
为我的后代问题添加另一个答案。我最近在打高尔夫球时用的一句话是:
;@(,.&.> <\)@i. 3
0 0
1 0
1 1
2 0
2 1
2 2
另一个稍微长一点的选择:
>@(>:/ #&, {@;)~@i.
例如:
>@(>:/ #&, {@;)~@i. 3
0 0
1 0
1 1
2 0
2 1
2 2
这个问题经常出现,我总是发现自己在与它作斗争。所以我想要最终的解决方案,如果有的话。
根本问题归结为这个冲突:
- J 喜欢使用同类列表/tables 等(即没有包含不同长度项目的列表,例如)
- 有时您想将一个动词应用于列表的每个项目,其中动词的结果本身就是一个项目数量不同的列表。
这通常在函数式语言中使用 chain
(或 flat_map
)来解决。
演示一般问题的示例
举一个具体的例子,假设您想列出列表 0 1 2 3
中所有可能的对,其中第一个严格小于第二个:
0 1
0 2
0 3
1 2
1 3
2 3
当然,您可以 table ,/
或编目 {
以获得完整的叉积,然后进行过滤,这样您就只剩下上三角了:
即取,"0/~ i.4
的结果:
0 0
0 1
0 2
0 3
1 0
1 1
1 2
1 3
2 0
2 1
2 2
2 3
3 0
3 1
3 2
3 3
其实为了让几何更清晰,我们将其显示为;/"2 ,"0/~ i.4
:
┌───┬───┬───┬───┐
│0 0│0 1│0 2│0 3│
├───┼───┼───┼───┤
│1 0│1 1│1 2│1 3│
├───┼───┼───┼───┤
│2 0│2 1│2 2│2 3│
├───┼───┼───┼───┤
│3 0│3 1│3 2│3 3│
└───┴───┴───┴───┘
现在我们求的结果是三角形的上半部分。但是这种方法有缺点:
- 我们必须做双倍的工作。
- 我们必须引入一个单独的过滤步骤来删除我们不起作用的额外结果。
- 以上两件事掩盖了我们代码的意图。
使用 {
的解决方案有类似的问题。
如果……就好了
chain
方法看起来像这样:
g=. ,"0 i.
(g 0);(g 1);(g 2);(g"0 i.3);<(<@g"0 (1+i.3))
产生:
┌──┬───┬───┬───┬─────────────┐
│ │1 0│2 0│0 0│┌───┬───┬───┐│
│ │ │2 1│0 0││1 0│2 0│3 0││
│ │ │ │ ││ │2 1│3 1││
│ │ │ │1 0││ │ │3 2││
│ │ │ │0 0│└───┴───┴───┘│
│ │ │ │ │ │
│ │ │ │2 0│ │
│ │ │ │2 1│ │
└──┴───┴───┴───┴─────────────┘
最后两列接近我想要的,但在倒数第二列中,自动填充的麻烦掩盖了我们的结果,在最后一列中,我们正确的结果被装箱,但取消装箱 [=74= 】 补。
什么是解决此类问题的好方法(惯用 J)?
注意:我不是在寻找示例中问题的临时解决方案,而是chain
解决的一般问题的解决方案在其他语言中。
我认为这个答案对于你想要的来说太具体了,但它确实表明挑战的第 2 部分(可变长度结果)的解决方案是使用 each=:&.>
这样填充就可以了避免了。
(< 0 1 2 3) ;"1@:((],.>#[) each) 0 1 2 3
0 1
0 2
0 3
1 2
1 3
2 3
(< 0 1 2 3) ((],.>#[) each) 0 1 2 3
+---+---+---+--+
|0 1|1 2|2 3| |
|0 2|1 3| | |
|0 3| | | |
+---+---+---+--+
为我的后代问题添加另一个答案。我最近在打高尔夫球时用的一句话是:
;@(,.&.> <\)@i. 3
0 0
1 0
1 1
2 0
2 1
2 2
另一个稍微长一点的选择:
>@(>:/ #&, {@;)~@i.
例如:
>@(>:/ #&, {@;)~@i. 3
0 0
1 0
1 1
2 0
2 1
2 2