Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make a list of start-/end indices in Haskell?

I am trying to make a Haskell function that takes two strings as arguments, the first is the string we want to locate in the second argument, and return a list of tuples with the start- and end indices of every occurrence. For example,

indexTuples :: String -> String -> [(Int, Int)]
indexTuples "aa" "foobaarfoobaar" 

Output: [(4,5), (11,12)] 

So far I have made a helping function that finds the indices ( I am trying to not use any extra methods other than Prelude methods, but implement by myself).

My helper function takes a string and a char and gives back the indices like so:

findPos :: (Num a1, Enum a1, Eq a2) => [a2] -> a2 -> [a1]
findPos str c = [index | (x, index) <- zip str [0..], x == c]

(I found this solution here.) This function zips the string with the infinite list of numbers into tuples, and then selects the tuples where the character equals the argument c and returns the index for each of them. This gives me this output:

Ok, one module loaded.
ghci> findPos "blablabla" 'b'
[0,3,6]

But how do I do this so that it takes in two strings instead? Like this:

ghci> findPos "blablabla" "bl" 
[(0,1), (3,4), (6,7)] 

I tried to just change the c from a char to a string object, but then I get several errors in ghci.

like image 491
Mampenda Avatar asked Nov 06 '22 00:11

Mampenda


1 Answers

A (non-empty) string has a head element, a Char:

indexTuples :: String -> String -> [(Int, Int)]
indexTuples []     _   = []
indexTuples (c:cs) str =

Having found its index in the other string, -- a list of them for all the occurrences, -- using the function findPos which you already have,

  let
    ixs = findPos str c

we try each one of them

    len = length cs
    fits = [ (i,i+len) | i <- ixs, cs == (take len $ drop i str)]

and that's our answer.

   in
      fits
like image 74
Will Ness Avatar answered Nov 14 '22 01:11

Will Ness