Вы можете упростить исходное определение до:
mainDiagonal :: [[a]] -> [a]
mainDiagonal [] = []
mainDiagonal (x:xs) = head x : getDiagonal (map tail xs)
Нет ничего особенного в использовании индексации для этого, что позволяет упростить его до:
mainDiagonal xs = zipWith (!!) xs [0..]
Представление на основе массива
Вы также можете представлять матрицы, используя Data.Array , проиндексированный (i,j)
. Это позволяет вам использовать математическое определение главной диагонали почти дословно:
import Data.Array
mainDiagonal :: (Ix i) => Array (i, i) e -> [e]
mainDiagonal xs = [ e | ((i,j),e) <- assocs xs, i == j ]
Вы можете использовать это как:
-- n×n matrix helper
matrix n = listArray ((0,0),(n-1,n-1))
> mainDiagonal $ matrix 3 [1..]
[1,5,9]
Эффективность
Предыдущее определение mainDiagonal
все еще неэффективно: ему все еще нужны тесты O (N²) i == j
. Аналогично версии zipWith
, ее можно исправить и обобщить следующим образом:
mainDiagonal xs = (xs !) `map` zip [n..n'] [m..m']
where ((n,m),(n',m')) = bounds xs
Эта версия индексирует только массив O (N) раз. (В качестве бонуса он также работает с прямоугольными матрицами и не зависит от базы индексации.)