3

this function that takes in a list of lists and returns the shortest one (returns an empty list if the list of lists is empty)

for example shortest [[1,2,9],[3,4],[1,2,3,5]] would return [3,4]

shortest :: [[a]] -> [a]

im new to haskell any help would be greatly appreciated thanks

programming
  • 51
  • 1
  • 5
  • 3
    It seems this question already has a few good answers. However, in the future, it's polite to say what you have tried, along with where and why you got stuck. – Daniel Wagner Oct 26 '13 at 17:09

4 Answers4

10

Prelude> :m +Data.List
Prelude Data.List> :m +Data.Function
Prelude Data.List Data.Function> minimumBy (compare`on`length) [[1,2,9],[3,4],[1,2,3,5]]
[3,4]

How it works – well, minimum is quite obvious. But we don't want to compare the number lists by the default lexicographical ordering, rather we want to specify what property exactly is compared – namely, the length. compare`on`ᴘʀᴏᴘᴇʀᴛʏ is a simple-to memorise general trick to do that, it uses

Data.Function.on :: (b->b->c) -> (a->b) -> a->a->c
compare :: Ord a => a -> a -> Ordering

so (compare`on`) is Ord b => (a->b) -> a->a->Ordering, i.e. we get a comparison function for any data type if we can supply a function that yields a comparable property. In our case, that is length.

Finally, we need to use that ordering for actually selecting the minimum element. The function that does the trick is Data.List.minimumBy.


Note that this solution isn't really efficient: it will apply length more that once to each list. You shouldn't use it for finding the shortest list amongs many thousands, with hundreds of elements each. There exist of course better algorithms, but they aren't as easy and concise.

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
  • 3
    You can also use the `comparing` function from `Data.Ord`. Then you can do `minimumBy (comparing length) [[1,2,9],[3,4],[1,2,3,5]]`. This also almost reads as plain english, which is nice. – bheklilr Oct 26 '13 at 15:10
  • Good point, that's kind of canonical then. Though I'd consider "minimum by compare on length" perhaps even closer to plain english than "minimum by comparing length", and also it's of course more general (e.g. `nubBy ((==)\`on\`length)`). – leftaroundabout Oct 26 '13 at 20:45
5

I would like to expand the solution presented by @leftaroundabout.

Prelude Data.List Data.Function> minimumBy (compare `on` (map . const $ 1)) [[1..],[5..11],[3,4]]

Unlike the original solution, this one definitely works with infinite lists.

Sassa NF
  • 5,306
  • 15
  • 22
3
shortest [y] = y    --base case: if there's only one element left, return it.
shortest (x:y:lst)  --extract the first two elements x, y from the list.  
    | length x > length y = *recursion*  
    | otherwise = *recursion*

You can solve this using recursion. I basically list out the structure for you, but you should think of how to implement the recursion part. Remember recursion takes place when a function calls itself.

Hint: use colon to concatenate the shortest element back to the original list, so that you can compare it to the next element in the list.

Hope it helps!

yfan
  • 101
  • 4
  • Well, you can of course solve _any_ problem using recursion (or else, in no other way either). However, when there are higher-order functions that abstract away this burden from you, it's generally a good idea to use them. If you have efficiency concerns about the super-short solution with `minimumBy`, you can still use a fold, that would here be equivalent to the explicit-recursion solution you're pointing towards. – leftaroundabout Oct 26 '13 at 20:56
  • I understand your concern. I just thought recursion is the way to go considering he/she is new to Haskell. @leftaroundabout – yfan Oct 27 '13 at 15:20
  • Hm. On one hand, I disagree – Haskell is build in such a way that higher-order functions are particularly easy to use, and they tend to be substantially clearer, easier to refactor etc. than explicit recursion. OTOH, it is inevitable to grasp recursive approaches at some point, and that's perhaps even simpler than folds. At least [Chakravarty & Keller recommend teaching recursion before higher-order solutions](http://www.cse.unsw.edu.au/~chak/papers/teaching-prgm.ps.gz), so... ok – agreed, +1. – leftaroundabout Oct 27 '13 at 16:44
  • Thanks :) I agree with you that Haskell's higher-order functions are handy and cleaner in general, and I also think recursion is the fundamental of higher-order functions. @leftaroundabout – yfan Oct 27 '13 at 20:07
0

First you need comparing from Data.Ord

import Data.Ord

Then give minimumBy the comparing function which compares by length

minimumBy (comparing (length)) [[1,2,9],[3,4],[1,2,3,5]]
Cameron White
  • 542
  • 4
  • 10