【问题标题】:Abstracting boxed array structures in J在 J 中抽象盒装数组结构
【发布时间】:2011-02-28 10:04:29
【问题描述】:

我一直在研究一个 J 函数,它应该扫描一个列表并将一个元素的连续副本放入单独的连接框中。我的努力已经把我带到了功能

(<;. 2) ((2&(~:/\)),1:)

它测试连续的列表条目是否不相等,返回一个布尔值列表,并将列表切割成每次出现数字 1 时结束的框。这是一个示例应用程序:

   (<;. 2) ((2&(~:/\)),1:) 1 2 3 3 3 4 1 1 1
+-+-+-----+-+-----+
|1|1|0 0 1|1|0 0 1|
+-+-+-----+-+-----+

如果我可以用输入参数中的相应值替换所有这些布尔值,那么任务就完成了。我一直在寻找某种神秘的功能,可以让我做类似的事情

   final =: mysteryfunction @ (<;. 2) ((2&(~:/\)),1:)

   final 1 2 3 3 3 4 1 1 1    
+-+-+-----+-+-----+
|1|2|3 3 3|4|1 1 1|
+-+-+-----+-+-----+

在理想情况下,会有一些方法可以抽象地表示(&lt;;. 2) ((2&amp;(~:/\)),1:) 生成的嵌套模式并将其应用于原始输入列表。 (即“这里的这个装箱数组的第一个元素在深度一装箱,第二个元素在深度一装箱,第三、第四和第五个元素在深度一装箱......,所以把那个未装箱的列表放在那里并以相同的方式将其装箱。”)我尝试使用 ;.S:L:L.&amp;. 来产生这种行为,但我运气不佳。是否有某种我缺少的运算符或原则可以使这种情况发生?如果我对整个问题进行了过度思考,这不会让我感到惊讶,但我的想法已经不多了。

编辑:

目前,我唯一可行的解​​决方案是这个:

isduplicate =: ((2&(~:/\)),1:)

testfun =: 3 : 0
numduplicates =. #S:0 ((<;.2) isduplicate y)
distinctboxes =. <"0 (isduplicate#]) y
numduplicates # each distinctboxes
)

这是一个两步过程,生成列表的游程编码,然后撤消编码而不删除框。由于我最初这样做的目的是使用 J 和 Haskell 串联解决 99 problems,所以如果我通过首先解决问题 12 来解决问题 9,感觉就像在乞求这个问题。

【问题讨论】:

    标签: tacit-programming j multidimensional-array


    【解决方案1】:

    你快到了。添加~ 并以不同的方式放置括号,就是这样:

       (<;.2~ (2&(~:/\) , 1:)) 1 2 3 3 3 4 1 1 1
    ┌─┬─┬─────┬─┬─────┐
    │1│2│3 3 3│4│1 1 1│
    └─┴─┴─────┴─┴─────┘
    

    快速解释/说明:

       s =: 1 2 3 3 3 4 1 1 1
    
       f =: 2&(~:/\) , 1:
       f s
    1 1 0 0 1 1 0 0 1
    
       g =: <;.2
    
       (f s) g s
    ┌─┬─┬─────┬─┬─────┐
    │1│2│3 3 3│4│1 1 1│
    └─┴─┴─────┴─┴─────┘
    

    现在最后的(f s) g s,有时被称为“左钩”,可以写成(g~ f) s(副词~在J中被称为“被动”,Haskell对应物是flip)。或者你也可以默认把这个写成fork(f g ]) s

    Chapter 9 of "Learning J" 广泛讨论此主题,如果您想了解更多信息。

    更新:我之前使用了基于分组的(&lt;/.~ (+/\&amp;(1,(2&amp;(~:/\))))),但您原来的基于剪切的方法比这更优雅(也更短)。由于这实际上是关于左钩拳,因此我更新为直接使用您的方法。

    【讨论】:

    • 原来如此!我花了几天时间研究文档,试图让 J 使用布尔输出将框应用于元素。感谢您的帮助。
    • 不客气。再看一遍,我可能应该 提到这使用 dyadic cut (;.2) 而不是在原始代码中单子使用 cut。最后一句话:如果我们想要代码简洁(以及清晰,imo),我可能会使用 cut-1 变体(而不是 cut-2)来写这个,它在前导 1 上分裂:(&lt;;.1~ 1,2&amp;(~:/\)) --美味多汁!
    【解决方案2】:

    我认为你想多了。需要完全默契吗?这是我刚刚拼凑的东西:

       s<;.2~  ((2&(~:/\)),1:) s=:1 2 3 3 3 4 1 1 1
    ┌─┬─┬─────┬─┬─────┐
    │1│2│3 3 3│4│1 1 1│
    └─┴─┴─────┴─┴─────┘
    

    显然,它只是将输入列表分配给 s,然后将其放入 ;. 表达式中。如果它需要完全默契,我相信你可以按摩它以将输入列表分解为布尔列表,然后使用{. &lt; ;.2 {: 之类的东西来获取输出。

    【讨论】:

      【解决方案3】:

      我想到的这个版本的功能更好,但仍然不够默契,无法完美。 (至少它不会为未来的另一个问题提出问题,无论如何。)一旦我弄清楚如何将 while 循环的逻辑表示为默认表达式,我就准备好了。

      NB. boxmerge takes a boxed argument and razes the first two
      NB. elements together into a new box.
      boxmerge =: [:}.]1}~[:<[:;2&{.
      
      NB. conseq checks to see whether the first two boxes of a boxed
      NB. array contain the same distinct element. (By assumption, each
      NB. box contains only one distinct element.) The name is an
      NB. abbreviation of the question, "consecutive boxes equal?"
      conseq =: [:=/[:~.&.>2&{.
      
      partfun =: ]`(boxmerge)@.conseq ^:_
      
      listpack =: 3 : 0
      mylist =. y
      listbin =. >a:
      while. (mylist -: (>a:)) = 0 do.
       newlist =. partfun mylist
       listbin =. listbin,{. newlist
       mylist =. }. newlist
      end.
      listbin
      )
      

      while 循环背后的想法是将partfun 应用于一个列表,将它的头放到另一个列表上,斩首原始列表,然后继续这样做,直到原始列表完全清空。我觉得真的应该有一种方法可以用默认的表达方式来表示这种逻辑。 (事实上​​,我想我什至在在线文档中看到过。)我只是想不出我需要输入的^:$:@. 的适当顺序棺材上的最后一颗钉子。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-14
        • 2021-11-11
        • 1970-01-01
        • 2023-01-30
        • 2017-10-22
        • 2017-12-05
        相关资源
        最近更新 更多