2011-03-06 95 views
5

在Haskell中,有两个函数允许对项目列表执行操作,以便将其减少为单个值。 (当然有两个以上,但这些是我感兴趣的两个。)他们是foldl1foldr1。如果要执行的操作是commutative(如添加),则使用这些操作并不重要。结果将是相同的。但是,如果操作是而不是可交换(例如,减法),则这两者产生非常不同的结果。例如:在J中实现Haskell foldl1的最有效方法是什么?

foldr1 (-) [1..9] 
foldl1 (-) [1..9] 

答案是第一个是5,第二个是-43。歼等效的foldr1是插入副词,/,例如

-/ 1+i.9 

其为foldr1 (-) [1..9]等效。我想在J中创建一个类似于插入副词的副词,但向左折叠而不是向右折叠。我能想出的最好的是以下几点:

foldl =: 1 : 'u~/@|.' 

因此,我们可以说:

- foldl 1+i.9 

,并得到-43的答案,这是从左侧倍的预期。

在J中有更好的方法吗?出于某种原因,颠倒y的论点对我来说似乎并不高效。也许有一种方法可以做到这一点,而不必诉诸于此。

+1

我不知道是否有除了翻转数组之外的东西,不管它看起来多么实用。人们会认为(或者希望)Haskell不会那么做,只是从最后起作用... – MPelletier 2011-03-07 16:04:09

+0

我的意思是“不管多么实际。” – MPelletier 2011-03-07 16:16:08

回答

2

我不认为这是一个更好的方式来倍左比你描述:

(v~)/(|. list) 

这是一个非常自然的方式,是一个几乎“文本”执行的定义。反转列表的成本非常小(imo)。

执行左折叠的其他显而易见的方法是设置

new_list = (first v second) v rest 

如:

foldl_once =: 1 :'(u/0 1 { y), (2}. y)' 
foldl =: 1 :'(u foldl_once)^:(<:#y) y' 

这样:

- foldl >:i.9 
_43 

而是用自己的方式进行优于这在空间和时间。

+0

我给你奖,虽然ephemient的回答很有趣,因为我认为很明显,我的解决方案可能是最好的,但我无法证明它。 – 2011-03-12 22:33:32

1
($:@}:-{:)^:(1<#) 1+i.9 
_43 

不知道它是否有更多(或更少)的效率。

+0

很难说。在4500以下的数字,您的解决方案和我的即时。之后,你的导致堆栈错误,我的工作很好。所以从这个意义上说,我的效率更高,但除了资源之外很难说哪个更快。 – 2011-03-08 05:27:02

+0

哦,我想我会补充说你的聪明和教育。 – 2011-03-08 05:27:26

相关问题