user1559027
user1559027

Reputation: 343

Sorting lists inside vectors of vectors

I have data like the following:

[["i2" "i1"]
 ['("red" "blue" "green" "yellow") '("C" "D" "A" "B")]]

I am trying to get it into the following format:

[["i1" "i2"]
 ['("A" "B" "C" "D") '("blue" "green" "red" "yellow")]]

Basically, I am trying to:

  1. Sort each list alphabetically
  2. Sort the first inner vector alphabetically
  3. Sort the rearrange the second inner vector to have the same, new order as the first inner vector

This is proving to be a difficult task for me. I tried constructing something like a three-level walk, but that did not work. I am trying to be idiomatic using the various map and walk functions, but maybe I just use "Do" and define a custom sorting map. It's pretty challenging.

Upvotes: 2

Views: 101

Answers (3)

A. Webb
A. Webb

Reputation: 26446

(def data [["i2" "i1"] ['("red" "blue" "green" "yellow") '("C" "D" "A" "B")]])

(defn transpose [m] (apply mapv vector m))

(defn arrange [[x y]] (->> [x (map sort y)] transpose (sort-by first) transpose))

(arrange data) 
;=> [["i1" "i2"] [("A" "B" "C" "D") ("blue" "green" "red" "yellow")]]

Upvotes: 2

DanLebrero
DanLebrero

Reputation: 8591

The replace fn is what you are looking for:

(defn my-sort [[cols vals]]
  (let [ vals-sorted (map sort vals)
         cols-sorted (sort cols)
         cols->sorted-vals (zipmap cols vals-sorted)]
    [cols-sorted
     (replace cols->sorted-vals cols-sorted)]))

Upvotes: 1

galdre
galdre

Reputation: 2339

Here's how I would approach a problem like this to come up with a solution.

(defn rearrange [[cols vals]]

First, I'd note that I'm trying to sort ["i2" "i1"] and rearrange the following list similarly. So I'll just tack the cols and value lists together:

    (let [pairs (map list cols vals)]

Now pairs is a collection of data structures looking like: ("i2" ("red" "blue" "green" "yellow")). You want the function to return a vector.

        (vector

Let's sort the pairs and grab the first item from each.

            (mapv first (sort-by first pairs)) 

mapv is just the same as (vec (map ...)). sort-by sorts pairs by comparing (first item).

If we replace the first instance of first in the line above with second, then we get the corresponding lists of values in the correct order. But those lists won't themselves be sorted. So we add that:

            (mapv (comp sort second) (sort-by first pairs)))))

End result:

(defn rearrange [[cols vals]]
    (let [pairs (map list cols vals)]
        (vector
            (mapv first (sort-by first pairs)) 
            (mapv (comp sort second) (sort-by first pairs)))))

It's not the nicest version of the function you can write, but half the battle is getting to this point. If you understand how this works, you can start improving it.

(def data [["i3" "i1" "i2"]
           ['("a" "c" "d" "b")
            '("elephant" "zebra" "tiger" "cat")
            '("red" "yellow" "blue" "green")]])
user=>(rearrange data)
[["i1" "i2" "i3"]
 [("cat" "elephant" "tiger" "zebra")
  ("blue" "green" "red" "yellow")
  ("a" "b" "c" "d")]]

Upvotes: 3

Related Questions