Reputation: 517
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
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 Plateau
s.
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
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