Skyfe
Skyfe

Reputation: 581

Haskell reorder list by matching value

I was wondering if there's an efficient/easy way to reorder a list of a list in by matching values of another list that sets the order. More specificly, if I'd have the following list:

[["a", "1", "2"], ["b", "2", "3"]]

I'd like to order it with the following list:

["b", "a"]

resulting in the newly ordered list:

[["b", "2", "3"], ["a", "1", "2"]]

Does anyone know how this can be done?

Thanks in advance!

Best Regards, Skyfe.

Upvotes: 5

Views: 707

Answers (1)

daniel gratzer
daniel gratzer

Reputation: 53871

Basically this works by providing a special ordering function,

import Data.List
import Data.Ord
byLoc :: Eq a => [a] -> -- The list that we're sorting by
                 [a] -> -- First list
                 [a] -> -- Second list
                 Ordering
byLoc ords = comparing (elemIndex . head)

comparing takes a function that takes in the two lists, and looks up the first element of each in our ordering list, comparing the location.

Then we just have

sortLoc ords = sortBy (byLoc ords)

and we're done. Unfortunately, this is really slow.

A faster solution is

import Data.Maybe
import Data.List
sortLoc ords xs = mapMaybe lookup ords
  where lookup e = find ((==e) . head) xs

Here we're just looking up the appropriate element in our list in the mapMaybe. If no element is found, then we just skip it.

Or if you want to support multiple elements with the same key

sortLoc ords xs = mapConcat lookup ords
  where lookup e = filter ((==e) . head) xs

Upvotes: 6

Related Questions