Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elegant way to return the longer of two strings

Tags:

haskell

I'm trying to write a function that returns the longer of two strings. So far this is what I have:

maxString :: String -> String -> String
maxString a b
    | (length a) > (length b) = a
    | otherwise = b

This works, but I'm wondering if there is a more elegant way to write this. Note: the two arguments cannot be in a list. They must be separate arguments to allow for currying.

Thoughts?

like image 872
dopatraman Avatar asked Jun 09 '15 23:06

dopatraman


Video Answer


4 Answers

So far all answers except Tejing's fully traverse both arguments. This one only traverses as far as the end of the shorter one.

longest a b = l' a b where
  l' _ [] = a
  l' [] _ = b
  l' (_:ar) (_:br) = l' ar br
like image 174
Jeremy List Avatar answered Sep 29 '22 09:09

Jeremy List


Played around with this one a bit. I wanted it to be a one-liner as well as having complexity O(min(n,m)). (ie. working even with infinite lists)

maxList :: [a] -> [a] -> [a]
maxList s s' = if s == zipWith const s s' then s' else s
like image 22
Alec Avatar answered Sep 29 '22 10:09

Alec


You can use existing Haskell facilities in Data.Ord and Data.Function and obtain a one-liner as follows:

maxString' x y = maximumBy (compare `on` length) [x, y]

Code:

import Data.Ord
import Data.Function
import Data.List

maxString' x y = maximumBy (compare `on` length) [x, y]

*Main> maxString' "ab" "c"
"ab"

-- EDIT --

As @DavidYoung pointed out,

compare `on` length

above can also be written in a shorter form: comparing length

like image 44
thor Avatar answered Sep 29 '22 11:09

thor


That's pretty much the most concise way to write it. However, the version below will terminate even when one list is infinite (O(min(a,b)) instead of O(a + b)).

compareLengths :: [a] -> [b] -> Ordering
compareLengths [    ] [    ] = EQ
compareLengths (a:as) [    ] = GT
compareLengths [    ] (b:bs) = LT
compareLengths (a:as) (b:bs) = compareLengths as bs

maxList :: [a] -> [a] -> [a]
maxList a b = case compareLengths a b of
  GT -> a
  _  -> b

Also, there's no real reason to limit your function to just Strings when it would make sense for arbitrary lists.

like image 22
Tejing Avatar answered Sep 29 '22 10:09

Tejing