2次元リストの全要素の周囲の和を求める
例えば、以下のようなmatrixが与えられる
code:_
[
]
これらの各セルの周囲の和を求める
今回は、自分自身と周囲の和を求めることにする
周囲だけ欲しければ後から自分自身を引けばいいだけなのでmrsekut.icon
code:hs
neighbors xss = zipWith (zipWith (-)) (neighborhoodSum xss) xss
例えば、1行目の1列目 (左上)の0の周囲の和は
0(自分自身) + 1(右) + 1(下) + 0(右下) = 2
例えば、中央の0の周囲の和は
上記の3 * 3のmatrixの全セルの和なので、4
これを全セルに対して行う
今回の例だと9個のセルすべて
当然、3 * 3であるとは限らない
これをどのようにして求めるか
シグネチャ
code:hs
neighborhoodSum :: Int -> Int
実例
いくつもの方法が考えられる
各セルごとに座標を持たせ、座標で計算する
modelを定義しちゃって、up, leftとかで取得できるようにする
3 * 3のwindowをスライドしていく
etc.
隣接する行同士を足し、その後、隣接する列同士を足すという方針
(もちろん順序は逆でもいい)
これは、この法則を見つけさえすれば、かなり単純に書けるmrsekut.icon
https://gyazo.com/93deba469fc2088011f5db4da0fa0116
code:hs
-- >>> neighborhoodSum 1,2,3],4,5,6,[7,8,9 neighborhoodSum :: Int -> Int
neighborhoodSum = rowSum . colSum
where
colSum = map windows3Sum
rowSum = transpose . map windows3Sum . transpose
windows3Sum = map sum . windows3 . padding
windows3 xs = [ x, y, z | (x:y:z:_) <- tails xs ] windows3
あまり意味はないが、対象性をきれいに書ける
code:hs
neighborhoodSum :: Int -> Int
neighborhoodSum = t . t
where
t = transpose . map sumAdjacent
transposeを使わない多相版
code:hs
-- >>> neighborhoodSum 1,2,3],4,5,6,[7,8,9 neighborhoodSum :: Int -> Int
neighborhoodSum = map smoothCols . smoothRows
where
smoothCols = trips add3 0
smoothRows = trips (zipWith3 add3) 0,0.. trips :: (a -> a -> a -> b) -> a -> a -> b trips f border = map (\a,b,c -> f a b c) . windows3 . padding border padding border xs = border : xs ++ border windows3 xs = [ x, y, z | (x:y:z:_) <- tails xs ] add3 :: Int -> Int -> Int -> Int
add3 a b c = a + b + c
3*3のwindowをslideして求める
code:hs
-- >>> neighborhoodSum 1,2,3],4,5,6,[7,8,9 neighborhoodSum :: Int -> Int
neighborhoodSum = map (map sum) . windows33 . padzeros
padzeros :: Int -> Int
padzeros = map col . row
where
row = padding =<< (*> 0) . head col = padding 0
padding border xs = border : xs ++ border windows33 = map (map concat . transpose . map windows3) . windows3
windows3 xs = [ x, y, z | (x:y:z:_) <- tails xs ] インデックスアクセスする
具体的になりがち
DSLを作る
modelを作る
up, left, などで取得できるようにする
大仰になりがち