Periodicity of a list in Haskell

0

I need to create a function in Haskell, that works in the following way

periodicidad :: [Integer] -> [Integer]
periodicidad [1,2,3,4,1,2,3,4...] = [1,2,3,4]
periodicidad [0,1,2,5,4,3,0,1,2,5,4...] = [0,1,2,5,4,3]

That is to say, that from a list you extract the part that is always crawling, what in Mathematical Sciences would be called period of a function.

I tried to group using group and cycle , but I do not get anything. I hope you can help me, I'm stuck and I do not know what to do.

    
asked by mathandtic 10.02.2018 в 19:43
source

2 answers

1

You can get all the sublists from the head with the function inits :

inits [1,2,1,2]
[[],[1],[1,2],[1,2,1],[1,2,1,2]]

Since the empty list does not interest us, we remove it with the function tail , which returns the tail of the list:

tail [[],[1],[1,2],[1,2,1],[1,2,1,2]]
[[1],[1,2],[1,2,1],[1,2,1,2]]

Now we filter from this list, with the function filter , the lists whose cycle are equal to the original list:

filter (\x -> take (length [1,2,1,2]) (cycle x) == [1,2,1,2]) [[1],[1,2],[1,2,1],[1,2,1,2]]
[[1,2],[1,2,1,2]]

Finally, we take the first list that fulfills this condition with the function head :

head [[1,2],[1,2,1,2]]
[1,2]

Putting it all together in a function:

import Data.List(inits)
period :: Eq a => [a] -> [a]
period xs = head $ filter (\x -> take (length xs) (cycle x) == xs) $ tail $ inits xs 

For example:

period [1,2,3,1,2,3,1,2,3]
[1,2,3]

period [1,2,1,2,1,2,1]
[1,2]
    
answered by 11.02.2018 / 13:05
source
0

Assuming that we are sure that the list has a period , it is enough to know when the first part of the list is a prefix of the rest. For this we have the functions inits and tails that give us all the initial parts and all the final ones, so it will be enough to compare them:

import Data.List (inits, tails, isPrefixOf)

periodo :: [Integer] -> [Integer]
periodo xs = head [ys | (ys,zs) <- tail (zip (inits xs) (tails xs))
                      , ys 'isPrefixOf' zs]

The tail is to avoid the first case, ([],xs) , since it would give us a false case.

Although this works in general, it fails when there is no period (eg: [1..10] )

We can give a more robust definition, ensuring that the period is repeated throughout the rest of the list:

import Data.List (inits, tails, isPrefixOf, cycle)
import Data.Maybe (listToMaybe)

periodo :: Eq a => [a] -> Maybe [a]
periodo xs =
  listToMaybe
     [ys | (ys,zs) <- tail (zip (inits xs) (tails xs))
         , zs 'isPrefixOf' cycle ys
         , (not.null) zs]
    
answered by 11.02.2018 в 13:44