9

I have a list of lists, let's say:

import Data.List

xs = [[1,2], [1,2,3], [2,3]]

I want to get the inner list with the most items, in this case [1,2,3].

I'm trying to use the maximumBy function from the Data.List library:

maximumBy (compare `on` length) xs

but I get the following error: not in scope 'on'

Can anyone tell me what is wrong, or if you have a better way to get the list?

dave4420
  • 46,404
  • 6
  • 118
  • 152
KevinCameron1337
  • 517
  • 2
  • 8
  • 16
  • As an exercise, try not to use `on`, instead writing the argument to `maximumBy` by hand: `maximumBy (\x y -> ...) xs`. – luqui Oct 11 '11 at 20:50

5 Answers5

9

on is defined in Data.Function, so you need to import that.

Alternatively, you can use comparing from Data.Ord:

maximumBy (comparing length) xs
interjay
  • 107,303
  • 21
  • 270
  • 254
8

While using maximumBy with comparing length or compare `on` length will do the job just fine for short lists, note that this is not a very efficient solution if the lists are long, since each time the algorithm compares two lists, it will re-calculate their lengths.

For example, if we have a very long first list, followed by many short lists, using maximumBy will be very slow since the length of the first list will be re-calculated at each step.

> import Data.List
> import Data.Ord
> let xs = replicate 50000 'a' : replicate 50000 "b"
> maximumBy (comparing length) xs
<snip>
(16.09 secs, 98338680 bytes)

We can get a more efficient solution by caching the lengths of the lists:

> let longest xss = snd $ maximumBy (comparing fst) [(length xs, xs) | xs <- xss]
> longest xs
<snip>
(0.35 secs, 91547296 bytes)

Of course, this might not make a big difference if your lists are small, but it's worth taking note of.

hammar
  • 138,522
  • 17
  • 304
  • 385
  • Isn't there any other non-recalculating version of `maximumBy`? Btw, how do you get `ghci` to print run-time? – Tarrasch Oct 11 '11 at 18:16
  • 1
    @Tarrasch: Not in any of the standard libraries, I think. Use `:set +s` to enable timing of each evaluation. – hammar Oct 11 '11 at 18:17
  • 1
    @Tarrasch: Apparently, [there was a proposal to add such functions](http://hackage.haskell.org/trac/ghc/ticket/2659), but it seems to have been abandoned. – hammar Oct 11 '11 at 18:29
4

Try

maximumBy (comparing length)

or

maximumBy (on compare length)

or

maximumBy (compare `on` length)
max taldykin
  • 12,459
  • 5
  • 45
  • 64
phimuemue
  • 34,669
  • 9
  • 84
  • 115
4

or you can make it a bit more explicit:

xs = [[1,2],[1,2,3],[2,3]]
ordLen a b = compare (length a) (length b)
maximumBy ordLen xs

maybe it's easier to understand this way.

Random Dev
  • 51,810
  • 9
  • 92
  • 119
1

Inspired by hammar's solution, but with just one pass thru the list:

import Data.List

longest = snd . foldl' cmp (0,[]) where
   cmp maxPair@(maxLen, _) list = 
      let len = length list 
      in if len > maxLen then (len, list) else maxPair  
Landei
  • 54,104
  • 13
  • 100
  • 195