Functional programming 在J中修改列表的元素,可以吗?

Functional programming 在J中修改列表的元素,可以吗?,functional-programming,j,tacit-programming,Functional Programming,J,Tacit Programming,我一直在J中使用lookandsay(OEIS A005150)的实现。我制作了两个版本,都非常简单,使用while.类型控制结构。一个递归,另一个循环。因为我有强迫性,我开始对版本进行比较计时 看,然后说是序列111121111221,它是,一个一个,两个一,等等 对于列表中的早期元素(最多20个),循环版本获胜,但只占很小的一部分。30左右的计时会导致递归版本获胜,如果堆栈空间足够支持递归版本,那么递归版本可能会更受欢迎。我研究了原因,我认为这与处理中间结果有关。序列中的第30个数字有580

我一直在J中使用lookandsay(OEIS A005150)的实现。我制作了两个版本,都非常简单,使用
while.
类型控制结构。一个递归,另一个循环。因为我有强迫性,我开始对版本进行比较计时

看,然后说是序列111121111221,它是,一个一个,两个一,等等

对于列表中的早期元素(最多20个),循环版本获胜,但只占很小的一部分。30左右的计时会导致递归版本获胜,如果堆栈空间足够支持递归版本,那么递归版本可能会更受欢迎。我研究了原因,我认为这与处理中间结果有关。序列中的第30个数字有5808位。(第32位,9898位,第34位,16774)

当您处理递归问题时,可以在递归调用中保留中间结果,最后的取消堆栈将生成结果,以便对结果进行最小的处理

在列表版本中,需要一个变量来保存结果。每次循环迭代都需要向结果中添加两个元素

在我看来,问题在于我无法在J中找到任何方法来修改现有数组,而不完全重新分配它。所以我是说

try. o =. o,e,(0&{y) catch. o =. e,(0&{y) end.
将一个元素放入o中,其中o在开始时可能没有值。这可能会明显慢于预期

o =. i.0
.
.
.
o =. (,o),e,(0&{y)
关键是,如果没有ravels,结果会得到错误的形状,或者看起来是这样。它以某种方式从i.0继承了一个形状

但是,即使像}amend这样的函数也不会修改列表,它们返回一个对列表进行了修改的列表,如果要保存列表,则需要分配它。随着分配列表的大小增加(当你从开始到结束进行下一个编号时),分配似乎需要越来越多的时间。这个赋值实际上是我能看到的唯一一件事情,它会使元素329898位在递归版本中花费更少的时间,而元素20(408位)在循环版本中花费更少的时间

递归版本使用以下内容生成返回:

e,(0&{y),(,lookandsay e }. y)
上面这一行既是函数的返回行,也是递归的返回行,因此当调用到达字符串末尾并且所有内容都取消堆栈时,整个返回向量将立即生成

在APL中,我认为人们可以说以下几点:

 a[1+rho a] <- new element
我对生成的数字的特征感兴趣。我发现如果你从1开始,数字永远不会超过3。如果你从一个大于3的数字开始,它将作为一个单体存在,你也可以从类似88888888的数字开始,生成一个数字,其中有一个9,在数字的末尾有一个8。但除了单身者,没有一个数字会高于3

编辑: 我又做了一些测量。我最初编写的程序接受向量或标量,其思想是在内部使用向量。我曾考虑过将向量从一层代码传递到另一层代码,但我仍然可能使用左参数来控制代码。当我传递顶级向量时,代码运行速度会大大加快,所以我猜大部分cpu都被从向量到数字的很长数字转换所消耗。递归例程在递归时总是向下传递一个向量,这可能是它几乎和循环一样快的原因

这并没有改变我的问题

我有一个答案,三个小时内我不能发布。我会发布的,请不要做太多的研究来回答它。

像这样的作业

arr=. 'z' 15} arr
执行到位。(有关其他受支持的就地操作,请参阅) 解释器确定仅更新了
arr
的一小部分,并且不会创建整个新列表以重新分配

在您的情况下发生的不是数组被重新分配,而是它以小的增量增长了很多倍,导致内存分配和重新分配


如果预先分配(通过为其分配一些大数据块),则可以使用
}
对其进行修改,而无需付出太多代价。

sverre在上面提供的链接()显示了支持修改现有数组而不是创建新数组的各种操作。这些措施包括:

    myarray=: myarray,'blah'
如果您对lookandsay序列的默认版本感兴趣,请参见RosettaCode:

   las=: ,@((# , {.);.1~ 1 , 2 ~:/\ ])&.(10x&#.inv)@]^:(1+i.@[)
   5 las 1
11 21 1211 111221 312211

在我问了这个问题之后,老实说,我失去了这个网站的踪迹

是的,答案是该语言没有表示“更新到位”的形式,但如果使用两种形式

x=:x,大多数情况下

x=:大多数事物}x

然后,解释器会识别出那些特殊的,并在适当的位置进行更新,除非它不能。解释器会识别出许多其他特殊的,比如:

199(1000和|@^)199

这种组合运算是模幂运算,它从不计算整个幂运算,就像

199(1000&| ^)199

如果没有,那就结束了


所以值得一读关于特价的文章。我会记下其他人的答案。

我最近注意到的一件事是,在两个布尔矩阵之间使用And(
*。
)的一次简单尝试导致内存崩溃,因为这两个布尔矩阵中的一个碰巧被存储为整数(尽管它仍然只是0和1)。强制提前转换为布尔值(简单地说是
1=
)解决了这个问题。我检查了,
I.0
解析为布尔值。我想知道你是否会通过欺骗J使其成为布尔值来获得更好的结果。使用
0$2
I.2-2
。这不是主要由?
las=,@((#,{.1~1,2~:/\])和(10x&&.inv 1+I)来解决吗@[)las 12334 |域错误:las | las 12334 las 1 |域错误:las | las 1 las=:3:,@(#,{.)1~
    myarray=: myarray,'blah'
   las=: ,@((# , {.);.1~ 1 , 2 ~:/\ ])&.(10x&#.inv)@]^:(1+i.@[)
   5 las 1
11 21 1211 111221 312211