プロジェクト内のマトリックスをリストのリストで表します[[a]]
これは良い考えですか、それとも配列を使用する方がよいでしょうか?
インデックス(i、j)を使用して要素をその場で変更するにはどうすればよいですか?
プロジェクト内のマトリックスをリストのリストで表します[[a]]
これは良い考えですか、それとも配列を使用する方がよいでしょうか?
インデックス(i、j)を使用して要素をその場で変更するにはどうすればよいですか?
もちろん、リストベースのソリューションは、キャッシュの局所性の問題をすべて伴う必要な間接化のために、最適化されたタイトな配列ほど高速になることはありません。ただし、これは一定のオーバーヘッド要因にすぎません(ただし、おそらくかなり大きいですが、100程度です)。
ただし、興味深いことに、行列へのネストされたリストのアプローチは、見た目ほど悪くはありません。リストは、従来の純粋関数型の方法で最も自然に処理されるデータ構造のままです。ミリムースが言ったように、純粋な方法で要素をインプレースで変更することはできません。1つの要素を変更して全体のコピーを作成する必要があります*。n✕n個の密配列行列の場合、これはO(n 2 )です。nが大きい場合はほとんど受け入れられません。
長さmのリストでのランダムアクセスはすでにO(m)であるため、配列の場合よりもはるかに悪くなりますが、より複雑な操作の場合はさらに悪くなることはありません。O(m )でリストを「変更」したり、 O(n )でn✕nのネストされたリストにアクセスしたり、O(n)でリストを変更したりできます。したがって、大きな行列に対して非破壊更新を実行する場合は、実際には。よりも高速です。[[a]]
Array a i
ああ、これがどのように機能するか–ええと、
type Matrix a = [[a]]
updateMatrixAt :: (Int,Int) -> (a->a) -> Matrix a -> Matrix a
updateMatrixAt(i,j) f mat
| (upperRows, thisRow : lowerRows ) <- splitAt i mat
, (leftCells, thisCell: rightCells) <- splitAt j thisRow
= upperRows
++ (leftCells ++ (f thisCell): rightCells)
: lowerRows
| otherwise = error "Tried to index matrix outside range"
トリックを行います。
*これを回避する試みがありましたが、これは行き止まりであることが証明されたと思います。本当に高いパフォーマンスが必要な場合は、ST
モナドで破壊的な更新を使用する必要があります。それほど良くはないかもしれませんが、問題はありません。
独自のデータ型をラッピングして使用するのはどうMap (Int,Int) a
ですか?要素の変更は簡単で、特にスパース行列の場合は多くのメモリを節約できます。