6

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

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?动词本身可以处理传递的值是否被装箱,这很好。另外,我宁愿避免转置矩阵 ( |:),因为它可能非常大。

4

3 回答 3

5

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

  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将列类型列表作为输入,并派生一个适合使用左手参数 to ;.(或类似运算符)的动名词。

因此:

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

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

   1 chain\"1 matrix

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

实际上,所做的是将1 chain\"1 matrix矩阵分成行("1),并且对于每一行,它创建一个 1 宽的移动窗口(- 矩阵每一行的宽数据窗口)。1 f\ matrixchainf

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

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

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

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

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

于 2013-07-08T22:17:44.120 回答
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 处应用动词(即应用于最高轴的每个项目。)

于 2011-08-02T17:10:02.027 回答
0

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

1 chain\"1 matrix

现在想明白了...

于 2011-08-03T02:41:41.000 回答