Home > OS >  Сoncatenation returns more elements than it should
Сoncatenation returns more elements than it should

Time:03-20

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]]"
  • Related