将矩阵的列递归求和到单行(使用 zipWith (+))

Recursive sum columns of matrix to single row (with zipWith (+))

lstsAdder :: [[Integer]] -> [Integer]
lstsAdder [] = []
lstsAdder (x:xs) = zipWith (+) x (lstsAdder xs)

正如标题所说,我希望它递归地添加这个:[[a,b,c],[d,e,f]] 像这样:[a+d,b+e,c+f],以及任何有限长度的列表列表。但是我所有的实现 returns 都是 []。为什么会这样,我该如何解决?

您的基本情况太基本了...该函数将递归地消耗所有行。当它一直沿着递归堆栈向下移动时,它只剩下空列表,即没有行的列表。这 returns 一个空结果。

但是,返回递归堆栈,每一层都应该用 + 压缩到它上面。好吧,但是用空列表压缩任何列表都会导致空列表!

您可以通过三种方式解决此问题:

  • 为单行矩阵添加一个额外的基本情况。如果只有一行,结果应该是只有那一行,对吗?

    lstsAdder [] = []
    lstsAdder [r] = r
    lstsAdder (x:xs) = zipWith (+) x $ lstsAdder xs
    
  • 在压缩步骤中用零填充缺失的元素。

    lstsAdder [] = []
    lstsAdder (x:xs) = x ^+^ lstsAdder xs
    
    infixrl 6 ^+^
    (^+^) :: [a] -> [a] -> [a]
    xs^+^[] = xs
    []^+^ys = ys
    (x:xs)^+^(y:ys) = (x+y) : (xs^+^ys)
    
  • 给出基本情况的无限零列表

    lstsAdder [] = repeat 0
    lstsAdder (x:xs) = zipWith (+) x $ lstsAdder xs
    

您的递归基本情况 returns []length (zipWith f a b) = min (length a) (length b)。这意味着您的结果将始终具有长度 0。min 的标识元素是 +infinity,(+) 的标识元素是 0,因此一种可能的基本情况是 repeat 0.

您还可以查看数据的先决条件是否允许您执行类似

的操作
import Data.List (transpose)
lstsAdder = map sum . transpose

它有不同的边缘情况行为(QuickCheck 给出 [[0,0],[0]] 作为一个示例输入)但也许这些边缘情况在实践中不会发生。

我相信你也可以用一个foldr1操作做如下;

listsAdd :: (Foldable t, Num c) => t [c] -> [c]
listsAdd =  foldr1 (zipWith (+))

*Main> listsAdd [[1,2,3],[4,5,6]]
[5,7,9]