Reputation: 777
Again I am stuck.
I have a list of pairs of strings [(String, String)]
and want to look for another String in it.
When the substring matches the first in the tuple, I'd like to return the second one and vice versa.
I had some ideas but again, I don't know how to correctly apply functions in Haskell.
My first idea was to use map
but that wouldn't really be able to give me a String as a result, would it?
I was thinking about using filter
. First searching the substring in the first of the pair and then in the second ones.
This is as far as I got:
search :: String -> [(String, String)] -> String
search substr xs = filter(==substr) xs.fst
And it doesn't even work :/
I'd be thankful for any kind of advice!
Thanks
Upvotes: 1
Views: 184
Reputation: 14578
You can call lookup
on the list, and then call lookup after swapping each tuple in the list. But this means possibly traversing the list twice.
lookup' k = foldl acc Nothing
where
acc (Just x) _ = Just x
acc _ (a,b) | k == b = Just a | k == a = Just b | otherwise = Nothing
This way you traverse the list only once. This version doesn't terminate on infinite lists if the element is present. You can write it using foldr, but that for that version, lookup' 0 [(0,1), undefined] == undefined
as opposed to the preferred behavior.
You can also write it using explicit recursion. For once, using explicit recursion is better! It covers both of the cases covered above:
lookup'' k [] = Nothing
lookup'' k ((a,b):xs)
| k == a = Just b
| k == b = Just a
| otherwise = lookup'' k xs
>lookup'' 1 [(1,0), undefined]
Just 0
>lookup'' 1 (zip [0..] [0..])
Just 1
Upvotes: 3
Reputation: 12749
user2407038's solution, lookup''
is the most efficient since it traverses the list only once, and terminates early when a match is found. It can be written without explicit recursion as follows:
import Control.Monad ( msum )
lookup'' k = msum . map match
where match (a, b) | k == a = Just b
| k == b = Just a
| otherwise = Nothing
Upvotes: 1
Reputation: 48644
I would suggest you to wrap the return type in Maybe
in case the substring isn't found.
search :: Eq a => a -> [(a, a)] -> Maybe a
search s xs = case lookup s xs of
Just x -> Just x
Nothing -> lookup s xs'
where xs' = map swap xs
If you don't want to wrap it with Maybe
, just use the fromJust
function and change the type signature accordingly. In the above code, you are using the library defined lookup
function. And in case the lookup fails in the first search you exchange the tuples and again perform the lookup
operation. Also, Don't forget to import swap
from Data.Tuple
.
Demo in ghci:
ghci > let a = [("hi","bye"),("cat", "dog")]
ghci > search "hi" a
Just "bye"
ghci > search "dog" a
Just "cat"
Upvotes: 4