I need get neighbours of cells on 1D closed field
for example:
neighbours [1,2,3,4,5,-1] (6 elements)
must return [[-1,1,2],[1,2,3],[2,3,4],[3,4,5],[4,5,-1],[5,-1,1]] (6 elements)
my code of neighbours
neighbours :: [a] -> [[a]]
neighbours l = concat [[[last l, head l, last $ take 2 l]], neighbours' l, [[l !! (length l - 2), last l, head l]]] where
neighbours' :: [a] -> [[a]]
neighbours' (a:b:c:xs) = [a, b, c]:neighbours (b:c:xs)
neighbours' _ = []
main = print $ neighbours [1, 2, 3, 4]
returns [[4,1,2],[1,2,3],[4,2,3],[2,3,4],[4,3,4],[3,4,3],[3,4,2],[3,4,1]] (8 elements), but expected [[4,1,2],[1,2,3],[2,3,4],[3,4,1]] (4 elements)
if I comment neighbours' l it return [[4,1,2],[3,4,1]] as expected (2 elements)
if you leave only neighbours' l it return [[1,2,3],[2,3,4]] as expected (2 elements)
2 2=4, but in this case for some reason it is 8
why it happens?
P.s.
neighbours' create middle of list
neighbours' [1,2,3,4,5,-1] == [[1,2,3],[2,3,4],[3,4,5],[4,5,-1]]
[last l, head l, last $ take 2 l] create head of list [-1,1,2]
[l !! (length l - 2), last l, head l] create last element of list [5,-1,1]
CodePudding user response:
Your code is somewhat hard to grasp because your two functions, neighbour
and neighbour
', are mutually recursive, which is sort of unusual.
The key line in your code is:
neighbours' (a:b:c:xs) = [a, b, c] : neighbours (b:c:xs)
If we assume that this is NOT intentional, and you meant to have just:
neighbours' (a:b:c:xs) = [a, b, c] : neighbours' (b:c:xs)
----------------------------------------------- ---------
then the code works as you seem to expect.
Note that having long (over 80 characters) lines of code makes the thing very difficult to debug.
Suggested code:
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ExplicitForAll #-}
import qualified Data.List as L
neighbours :: [a] -> [[a]]
neighbours l = concat [
[[last l, head l, last $ take 2 l]],
neighbours' l,
[[l !! (length l - 2), last l, head l]]
]
where
neighbours' :: [a] -> [[a]]
neighbours' (a:b:c:xs) = [a, b, c] : neighbours' (b:c:xs)
neighbours' _ = []
-- neighbour is British English, neighbor is US English
neighbors :: [a] -> [[a]]
neighbors xs =
let k = length xs
triplets = map (take 3) (L.tails (cycle xs)) -- raw material
in
take k $ drop (k-1) triplets -- take proper section of infinite list
main :: IO ()
main = do
print $ "res1 = " (show $ neighbours [1, 2, 3, 4])
print $ "res2 = " (show $ neighbors [1, 2, 3, 4])
Program output:
"res1 = [[4,1,2],[1,2,3],[2,3,4],[3,4,1]]"
"res2 = [[4,1,2],[1,2,3],[2,3,4],[3,4,1]]"