One way of doing it is to apply group
to each string:
> group "hhhh"
["hhhh"]
> group "plml"
["p","l","m","l"]
Then, if you takeWhile
the group count is 1, you'll get all the homogeneous strings:
> test = ["hello","help","hell","helm"]
> import Data.List
> takeWhile ((==1) . length) . map group . transpose $ test
[["hhhh"],["eeee"],["llll"]]
You can get rid of the extra list layer with map head
.
Also, it would actually be better to replace this test for single groups with a custom pattern match function:
single :: [a] -> Bool
single [a] = True
single _ = False
and use:
> map head . takeWhile single . map group . transpose $ test
["hhhh","eeee","llll"]]
The main difference is that (==1) . length
needs to evaluate and count the length of the whole set of groups, but single
can stop early. For example, on an infinite string:
> ((==1) . length) $ group $ "aaa" ++ repeat 'b' -- hangs forever
> single $ group $ "aaa" ++ repeat 'b' -- returns `False` at first 'b'
An alternative, suggested in the comments, would be to do a more direct check that the first character is equal to all the other characters:
allSame :: (Eq a) => [a] -> Bool
allSame (x:rest) = all (==x) rest
and:
> takeWhile allSame . transpose $ test
["hhhh","eeee","llll"]
SPOILERS:
As per your comments, you're trying to find the longest prefix, so to finish things off, note that you want to map head
across:
["hhhh","eeee","llll"]
to get:
['h','e','l']
which is the same as:
"hel"
Since map head
followed by map head
can be written map head . map head
, or even shorter map (head . head)
, the final definition using group
can be written:
prefix :: (Eq a) => [[a]] -> [a]
prefix = map (head . head) . takeWhile single . map group . transpose
where single [a] = True
single _ = False
and the final definition using allSame
can be written:
prefix :: (Eq a) => [[a]] -> [a]
prefix = map head . takeWhile allSame . transpose
where allSame (x:rest) = all (==x) rest