【问题标题】:A non-awkward way to "chain" in J?在 J 中“链接”的一种不尴尬的方式?
【发布时间】:2026-02-03 03:25:01
【问题描述】:

这经常出现,我总是发现自己在与它作斗争。所以我想要一个最终的解决方案,如果有的话。

本质问题归结为这个冲突:

  1. J 喜欢使用同类列表/表格等(例如,没有包含不同长度项目的列表)
  2. 有时您希望将动词应用于列表的每个项目,其中动词的结果本身就是一个项目数不同的列表。

这通常使用函数式语言中的chain(或flat_map)来解决。

演示一般问题的示例

举个具体的例子,假设你想列出列表0 1 2 3中所有可能的对,其中第一个严格小于第二个:

0 1
0 2
0 3
1 2
1 3
2 3

当然,您可以使用表格,/ 或目录{ 来获得完整的叉积,然后进行过滤,只剩下上面的三角形:

即取,"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│
└───┴───┴───┴───┘

现在我们寻找的结果是三角形的上半部分。但这种方法有缺点:

  1. 我们必须加倍努力。
  2. 我们必须引入一个单独的过滤步骤来删除我们不起作用的额外结果。
  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│             │
└──┴───┴───┴───┴─────────────┘

最后两列与我想要的很接近,但在倒数第二列中,自动填充会掩盖我们的结果,而在最后一列中,我们正确的结果被装箱,但取消装箱会返回填充。

什么是解决此类问题的好方法(也是惯用的 J)方法?

注意:我不是在寻找针对示例中问题的临时解决方案,而是针对chain 以其他语言解决的一般问题的解决方案。

【问题讨论】:

    标签: j


    【解决方案1】:

    我认为这个答案对于你想要的来说太具体了,但它确实表明挑战的第 2 部分(可变长度结果)的解决方案是使用 each=:&amp;.&gt; 以便可以避免填充。

       (< 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|   |   |  |
    +---+---+---+--+
    

    【讨论】:

    • 有没有一种方便的方法来获取一组不同大小的数组并将它们组合成一个平面列表?即把1;2 3;4 5 6变成1 2 3 4 5 6
    • 当然,使用; 1;2 3;4 5 6 返回1 2 3 4 5 6
    • 不是说chain f = ;@f吗?
    • 是的,你是对的。 ;"1 的排名 1 在答案中不是必需的。 (&lt; 0 1 2 3) ;@:((],.&gt;#[) each) 0 1 2 3 返回相同的结果
    • 感谢您今天和昨天的所有帮助!
    【解决方案2】:

    为我的后代添加另一个答案。我最近在打高尔夫球时使用的一句话是:

       ;@(,.&.> <\)@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
    

    【讨论】: