Twitter でいただいたアドバイスを元に、maxLineProd をワンライナーで書き換えてみた。
-- 横一列の連続する4つの数字の積の最大値を取得
maxLineProd :: Integer
maxLineProd = maximum $ map (\line -> (maximum . map product . (!! 4) . transpose . map inits . tails) line) grid
こんな形。
map (\line -> f line) grid は line 変数を使用せずに map f grid と書けるので
maxLineProd = maximum $ map (maximum . map product . (!! 4) . transpose . map inits . tails) grid
さらに各行の maximum のリストを作ってからそのリストの maximum を取って最終的な値を求めているところを
bind(逆bind?)に書き換えて
maxLineProd = maximum $ map product . (!! 4) . transpose . map inits . tails =<< grid
こうなった。
うーむ…確かに正しく動くが処理内容を理解できなかったので細かく解読していこう。
inits, tails はともに Data.List モジュールに定義されており、
inits は先頭から1要素ずつ取ったリストのリストを、tails は末尾から1要素ずつ除いたリストのリストを作る。
inits [1,2,3,4,5]
-- [[],[1],[1,2],[1,2,3],[1,2,3,4],[1,2,3,4,5]]
tails [1,2,3,4,5]
-- [[1,2,3,4,5],[2,3,4,5],[3,4,5],[4,5],[5],[]]
(map inits . tails) [8,2,22,97,38,15,0,40,0,75,4,5,7,78,52,12,50,77,91,8]
まず末尾1要素ずつ除いたリストのリストを作り、その各要素に対して先頭から1要素ずつ取ったリストのリストを作る。
第1要素が [[],[8],[8,2],[8,2,22],[8,2,22,97],[8,2,22,97,38],[8,2,22,97,38,15],[8,2,22,97,38,15,0]~
第2要素が [[],[2],[2,22],[2,22,97],[2,22,97,38],[2,22,97,38,15],[2,22,97,38,15,0]~となる。

transport も Data.List モジュールに定義されており、
リストのリストを取って、各リストの同一要素ずつをまとめたリストのリストを作る。
transpose [[1,2,3], [4,5,6],[7,8,9]]
-- [[1,4,7],[2,5,8],[3,6,9]]
(transpose . map inits . tails) [8,2,22,97,38,15,0,40,0,75,4,5,7,78,52,12,50,77,91,8] は、
第1要素が [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
第2要素が [[8],[2],[22],[97],[38],[15],[0],[40],[0],[75],[4],[5],[7],[78],[52],[12],[50],[77],[91],[8]]
第3要素が [[8,2],[2,22],[22,97],[97,38],[38,15],[15,0],[0,40],[40,0],[0,75],[75,4],[4,5],[5,7],[7,78]~
となる。
おお、ようやく欲しいものが見えてきた。

こうやって作ったリストのリストのリストから、(!! 4)を取ると、
[[8,2,22,97],[2,22,97,38],[22,97,38,15],[97,38,15,0],[38,15,0,40],[15,0,40,0],[0,40,0,75]~という
この行での全ての連続する4項目の組み合わせが得られる。
あとは各要素の積を算出して最大値を求める。
なるほど!

しかし、 transpose . map inits . tails は自分では絶対に思いつかなかった操作だな…。

Copyright© 2011-2021 Shunsuke Otani All Right Reserved .