J中的连锁动词

时间:2011-08-01 22:56:16

标签: j

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

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

列描述符:

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

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

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

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

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

3 个答案:

答案 0 :(得分:5)

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

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

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

  3. 步骤(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规范化输入&amp;每个列处理器的输出(即抽象出预处理和后处理,以便用户只需提供转换的动态“核心”)。动词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在处理“toto”中的数组时效果最佳;根据经验,您应该让原始或用户定义的名称在每个应用程序中查看尽可能多的数据。这是“columificaton”方法的主要好处:如果将数据存储为同类列的列表,以后操作会更快更容易。

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

       1 chain\"1 matrix
    

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

    实际上,1 chain\"1 matrix所做的是将矩阵分解为行("1),并且对于每一行,它创建一个1宽的移动窗口,(1 f\ matrix),应用chain对每个1宽窗口中的每个窗口的动词(即f随矩阵每行的每个1宽数据窗口而变化)。

    由于一行(一级-1矢量)的移动1窗口是行的原子,按顺序,chain的动词以相同的顺序给出,实际上你是将这些动词应用于矩阵的列,一。原子。在。一个。时间。

    简而言之:1 chain\"1 matrix类似于foo"0 matrix,除了每个原子的foo变化。并且应该避免出于同样的原因foo"0 matrix一般应该避免:因为应用小等级的函数会对J的粒度起作用,从而导致性能损失。

    一般情况下,最好尽可能在较高级别使用应用函数,在这种情况下,需要将matrix转换为({1}}到列式正常形式。

    换句话说,;. "1\"0columnify。如果您发现整个homogenize / 1 chain\"1 matrix过于冗长或过于庞大(与{{1}}相比),您可以导入[1]中提供的脚本,该脚本会将这些定义打包为可用的实用程序,带扩展。有关示例和说明,请参阅该页面。

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

答案 1 :(得分:2)

如果这些计算仅依赖于各个框内的数据(可能还有全局值),则可以使用Under with Under Open(又名每个)。该技术的应用如下所示:

   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 :(得分:0)

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

1 chain\"1 matrix

现在了解它......