【问题标题】:Chain verbs in JJ中的链式动词
【发布时间】:2011-08-01 22:56:16
【问题描述】:

假设一个包含各种类型的盒装矩阵:

matrix =: ('abc';'defgh';23),:('foo';'bar';45)
matrix
+----+-----+--+ |abc|defgh|23| +----+-----+--+ |富|酒吧 |45| +----+-----+--+

还有一个列描述符:

columnTypes =: 'string';'string';'num'

我想根据类型逐列在此矩阵上应用动词。我将使用动词 DoString 和 DoNum:

chain =: (('string';'num') i. columnTypes) { DoString`DoNum

编辑:列描述符很重要,使用哪个动词的决定取决于它们,而不是类型本身。实际上,我可以有多种类型的字符串、数字,甚至日期(在 J 中是数字)。

如何将chain 应用于matrix 的每一行?动词本身可以处理传递的值是否被装箱,这很好。另外,我宁愿避免转置矩阵 (|:),因为它可能非常大。

【问题讨论】:

  • 那种交易总是给我带来麻烦。是时候终于了解它了。

标签: j


【解决方案1】:

执行此操作的标准方法是:

  1. 将面向行(单元格)的结构转换为面向列的结构

  2. 对每一列应用正确的动词(仅一次)

步骤 (1) 很简单。步骤 (2) 也很简单,但不那么明显。有一个小技巧可以帮上忙。

诀窍是知道许多原始运算符接受动名词作为左参数并生成一个函数,该函数在动名词上循环,依次应用每个动词。 IMO,此类别中最有用的运算符是 ;. 。这是一个使用它的示例实现:

步骤 (0),输入:

   matrix      =:  ('abc';'defgh';23),:('foo';'bar';45)

   columnTypes =:  'string';'string';'num'

   DoString    =:  toupper
   DoNum       =:  0&j.

   matrix
+---+-----+--+
|abc|defgh|23|
+---+-----+--+
|foo|bar  |45|
+---+-----+--+

步骤(1),对数据进行分类:

   columnify   =:  <@:>"1@:|: :. rowify =: <"_1&>
   columnify matrix
+---+-----+-----+
|abc|defgh|23 45|
|foo|bar  |     |
+---+-----+-----+

请注意,columnify 提供了一个逆向,它将重新“行化”数据,尽管您不应该这样做:见下文。

步骤(2),使用;.的动词循环功能,将正确的动词应用于每一列(恰好一次):

   homogenize  =:  ({. foo&.>@:{.`'') [^:('foo'-:])L:0~ ]
   chain       =:  DoString`DoNum`] homogenize@{~  ('string';'num')&i.  

请注意,未知列类型的默认转换是恒等函数]

动词homogenize 标准化每个列处理器的输入和输出(即抽象出预处理和后处理,以便用户只需提供转换的动态“核心”)。动词chain 将列类型列表作为输入,并派生一个适合使用;.(或类似运算符)左侧参数的动名词。

因此:

   1 (chain columnTypes);.1  columnify matrix
+---+-----+---------+
|ABC|DEFGH|0j23 0j45|
|FOO|BAR  |         |
+---+-----+---------+

或者,如果您确实必须有一个 NxM 盒装单元格表,请应用剪切“下”列:

   1 (chain columnTypes);.1&.columnify matrix
+-----+-----+
|ABC  |FOO  |
+-----+-----+
|DEFGH|BAR  |
+-----+-----+
|0j23 |0j45 |
+-----+-----+

但请注意,在 J 上下文中,出于性能和符号方面的原因,将表保留为同类列的列表更为合适。

J 在“in toto”处理数组时效果最好;经验法则是您应该让原始名称或用户定义名称在每个应用程序中看到尽可能多的数据。这就是这种“columificaton”方法的主要好处:如果您将数据存储为同质列的列表,以后操作起来会更快、更容易。

但是,如果您的用例确实需要将数据保存为 NxM 盒装单元格表,那么将数据转换为列范式和从列范式转换是一项昂贵的空操作。在这种情况下,您应该坚持原来的解决方案,

   1 chain\"1 matrix

哪个(因为你问过)实际上与;. 方法在相同的前提下工作。特别是,\ 是另一个接受动名词参数并连续应用每个动词(即循环地应用于每个新的数据窗口)的原始运算符。

实际上,1 chain\"1 matrix 所做的是将矩阵分成几行 ("1),并为每一行创建一个宽度为 1 的移动窗口 (1 f\ matrix),应用 chain 的动词循环到每个 1 宽的窗口(即f 随矩阵每一行的每个 1 宽的数据窗口而变化)。

由于行的移动 1 窗口(rank-1 向量)是该行的原子,按顺序排列,并且chain 的动词以相同的顺序给出,实际上您正在应用这些矩阵列的动词,one。原子。在。一个。时间。

简而言之:1 chain\"1 matrix 类似于foo"0 matrix,除了每个原子的 foo 变化。出于同样的原因,应该避免使用foo"0 matrix,一般来说应该避免:因为在小等级上应用函数会违背 J 的纹理,从而导致性能损失。

一般来说,最好尽可能使用更高级别的应用函数,在这种情况下,这需要将matrix 转换(和维护)为列正常形式。

换句话说,在这里,;. 对应于"1,就像\ 对应于"0。如果您发现整个 columnify/homogenize 太长或太笨重(与 1 chain\"1 matrix 相比),您可以导入 [1] 中提供的脚本,它将这些定义打包为可重用的实用程序,并带有扩展名。有关示例和说明,请参见页面。

[1] 相关实用程序脚本:
http://www.jsoftware.com/jwiki/DanBron/Snippets/DOOG

【讨论】:

    【解决方案2】:

    如果这些计算仅依赖于单个框内的数据(也许还有全局值),则可以将 Agenda 与 Under Open(又名 Each)一起使用。该技术的应用如下所示:

       doCells  =: (doNum`doString @. isLiteral)&.>
       isLiteral=: 2 -: 3!:0
    
       doNum    =: +:   NB. Double
       doString =: toupper
    
       doCells matrix
    ┌───┬─────┬──┐
    │ABC│DEFGH│46│
    ├───┼─────┼──┤
    │FOO│BAR  │90│
    └───┴─────┴──┘
    

    (在此示例中,我为 doNumdoString 赋予了任意含义,以帮助使可行性变得清晰。)

    这里使用的isLiteral 版本可能就足够了,但如果涉及稀疏文字或unicode 值,它将失败。

    如果计算需要涉及比单个框更多的矩阵,这将不是您问题的答案。如果需要逐行计算,则解决方案可能涉及在 _1 级(即最高轴的每个项目)应用动词。

    【讨论】:

    • 如果我不想动态确定类型怎么办?假设我有 2 个用于字符串的动词,类型为“string1”和“string2”?
    • 我不应该使用类型。每一行的操作实际上都是相同的,对于单个矩阵,列将是“固定的”。
    • 在我的示例中,(DoString`DoNum @. 0 0 1) each matrix 会引发域错误。
    【解决方案3】:

    通过实验,我得到了这个做我想做的事:

    1 chain\"1 matrix
    

    现在明白了吧……

    【讨论】:

      猜你喜欢
      • 2011-05-16
      • 1970-01-01
      • 2014-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      相关资源
      最近更新 更多