Skip to content

Instantly share code, notes, and snippets.

@ericnormand
Last active March 14, 2021 20:46
Show Gist options
  • Save ericnormand/48b0a933294639bb27902eda062772e2 to your computer and use it in GitHub Desktop.
Save ericnormand/48b0a933294639bb27902eda062772e2 to your computer and use it in GitHub Desktop.
403 - PurelyFunctional.tv Newsletter

Sort by content

In this task, we are sorting a heterogeneous list of elements. The elements are either single numbers or sequences of numbers. We should sort them by numeric content, like this:

(sort-by-content [4 5 3 2 1]) ;=> [1 2 3 4 5]
;; we sort sequences by their first element, then by second element, then by third, etc
(sort-by-content [[2 3] [0 9] [-1 3 4] [0 3]]) ;=> [[-1 3 4] [0 3] [0 9] [2 3]]
;; we sort numbers and sequences together as if numbers were sequences of length 1
(sort-by-content [5 [4 5] 3 1 [0 2 3]]) ;=> [[0 2 3] 1 3 [4 5] 5]
;; but numbers sort before sequences when the number is the same as the first element
(sort-by-content [[1] 1]) ;=> [1 [1]]
;; don't sort subsequences
(sort-by-content [[10 3 4 1]]) ;=> [[10 3 4 1]]

Update: Someone asked if you need to sort the numbers in subsequences. You do not. Just sort the top-level values, the mix of numbers and sequences of numbers. I've added an example to clarify.

Thanks to this site for the challenge idea where it is considered Medium level in JavaScript.

Please submit your solutions as comments on this gist.

@mchampine
Copy link

@KingCode - really interesting alternative approaches!
Btw, if you want syntax highlighting on your code blocks, just add the word clojure after the 3 back-ticks at the start of the block.

@KingCode
Copy link

KingCode commented Nov 21, 2020

Thanks @mchampine! I can't believe I never noticed the syntax highlighting :0, will use it from now on..

Regarding this challenge, for me finding a solution was a tug-of-war b/w brevity and getting a pictorial view of the possible logic paths, but I am not convinced I did well in either ( e.g. I am sure there is a way to avoid using two conds in the label fn, perhaps by using another multi-method or core.match, and the core.match solution is awfully springled with constraints which pollute the pictorial view) - I would love to see suggestions/improvements on the idea!

In any case I enjoyed learning some more about defmulti and core.match!

@walterl
Copy link

walterl commented Mar 14, 2021

(defn- compare-nums
  [[x & xs] [y & ys]]
  (if (or (some? x) (some? y))
    (let [res (compare x y)]
      (if (zero? res)
        (compare-nums xs ys)
        res))
    0))

(defn- compare-content
  [x y]
  (let [res (compare-nums (:nums x) (:nums y))]
    (if (zero? res)
      (compare (:priority x) (:priority y))
      res)))

(defn- content-key
  [x]
  (if (coll? x)
    {:priority 1, :nums x}
    {:priority 0, :nums [x]}))

(defn sort-by-content
  [xs]
  (sort-by content-key compare-content xs))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment