KevinCameron1337
KevinCameron1337

Reputation: 517

Haskell: Remove largest list

I have a list of lists, and a function that returns the list with the most items:

extract ::[Plateau]->Plateau

extract(x:xs) 
  |x==maximumBy(compare `on` length)(x:xs)=x 
  |otherwise = extract(xs)
extract []=[""]

Now I need a function to take the same [Plateau] and return a new [Plateau] that has the previous largest removed:

prune::[Plateau]->[Plateau]
prune(x:xs)
  |x < (maximumBy(compare `on` length)(x:xs)=x : prune (xs)
  |x>=maximumBy(compare `on` length)(x:xs)=[]
prune [] = [] 

I also call prune with a sortBy as to make sure the largest list is last:

(extract . prune) (sortBy(compare `on` length)(plateaus))

This starts out to work correctly. my List plateaus looks like:

plateaus = ["01000"], ["01010", "11010", "10010"] ["00101"], ["01101", "01001"]]

here it is sorted:

 [["01000"], ["00101"], ["01101", "01001"], ["01010", "11010", "10010"]]

Now, my function prune is returning a list of

[["01000"], ["00101"]]

that tells me, for some reason Haskell thinks

["01101", "01001"] >= ["01010", "11010", "10010"]

When I can clearly see that 2 >= 3 is not true.

Why is this?

Upvotes: 3

Views: 328

Answers (2)

Nate
Nate

Reputation: 12819

Something like this might be a simpler choice, perhaps:

prune :: [Plateau] -> [Plateau]
prune s@(w:x:xs) = filter ( /= maxplateau ) s
    where maxplateau = maximumBy (compare `on` length) s
prune _ = []

This relies on several nice parts of Haskell.

The first is pattern matching - You used this in your question, and in your previous question - here, I'm taking it a step further, to require a list with at least two elements, w and x. This allows the fall-through case to handle both the empty- and single-entry-list cases, which should (based on the code you provided) result in the same thing: an empty list.

The second is to use the @ symbol, AKA as patterns. I showed you this in my answer to your previous question. While just syntactic sugar, and not required, it serves to make the code much more readable.

The third is currying, sometimes called "partial function application". In my case, I used what Learn you a Haskell calls partial application of an infix function using sections (you should read that whole section - very formative, does a very good job addressing a pillar of the Haskell language (in fact, if you actually like or want to get a good beginner's grasp of Haskell, I would read Learn you a Haskell cover to cover, as it's fantastic)). Anyhow, that's what I was using with ( /= maxplateau ); normally, the infix function /= takes two parameters of the same type, and returns a Bool - by wrapping in parenthesis and providing an expression on one side, I have partially applied it. This produces a function of one Plateau parameter, which is perfect to supply to the filter function on a list of Plateaus.

Finally, in my edit, I changed my answer a little to use the where keyword. This I did just to make that partial application a little clearer. I would encourage you to read more about where in the where section of Learn you a Haskell (can you tell I'm biased? :^) )

Upvotes: 8

Ganesh Sittampalam
Ganesh Sittampalam

Reputation: 29100

List comparison is lexicographic, not by length. So you get the result you see because "01101" >= "01010", which in turn is for the same reason - the first two characters of the two strings are equal and the third character of the first is greater than the third character of the second.

Upvotes: 6

Related Questions