I need to sort one list by the order of another, but I don't know how it can be done.
For example: I could have a list a
similar to:
[C, B, G, E]
And a list b
(that sets the order):
[A, B, C, D, E, F, G, ...]
(Just as example, these aren't the actual values though)
Then, list a
should be sorted the same way as List b
and thus become sorted to:
[B, C, E, G]
How to do this sorting by the order of another list?
Approach : Zip the two lists. Create a new, sorted list based on the zip using sorted(). Using a list comprehension extract the first elements of each pair from the sorted, zipped list.
There will be three distinct ways to sort the nested lists. The first is to use Bubble Sort, the second is to use the sort() method, and the third is to use the sorted() method.
If I understand, one of the lists give the relative order of all the elements of the other list. Ie:
> sortWithOrder [5,1,2,3,4] [1,2,3,4,5,5,4,3,2,1]
[5,5,1,1,2,2,3,3,4,4]
This piece of code should work :
module SortWithOrder where
import qualified Data.Map.Strict as M
import Data.List
import Data.Ord
sortWithOrder :: Ord a
=> [a] -- order list
-> [a] -- source list
-> [a]
sortWithOrder order = sortBy (comparing getOrder)
where
getOrder k = M.findWithDefault (-1) k ordermap
ordermap = M.fromList (zip order [0..])
Edit: a more efficient solution is to use sortOn
, like this:
sortWithOrder order = sortOn getOrder
You could also map the order to the list and sort it:
Prelude> let order = zip ["A", "B", "C", "D", "E", "F", "G"] [0..]
Prelude> let myList = ["C", "B", "G", "E"]
Prelude> import Data.List (sort)
Prelude> map snd . sort . map (\x -> (lookup x order, x)) $ myList
["B","C","E","G"]
Thus we can define this function as
sortAlong :: Eq b => [b] -> [b] -> [b]
sortAlong order = map snd . sortBy (comparing fst) . map (\x -> (lookup x z, x))
where
z = zip order [0..]
An Ord
constraint allows the more efficient route through Map
but this version needs just Eq
:
> sortAlong "ABCDEFG" "CBGE"
"BCEG"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With