How to verify if a list is sorted? - list

How can I, in Clojure, verify is a list of numbers is sorted?
(def my-list (list 1 2 3 1 4 2 2 4))
sorted? only returns true if the collection implements the sorted interface. I was looking for a reduce operation that would iterate the list pairwise, such as (reduce < my-list).
I understand I could manually create pairs and compare these:
(letfn [(pair [l] (if (= (count l) 2) (list l) (cons (take 2 l) (pair (rest l)))))]
(every? #(apply < %) (pair my-list)))
But that seems unnecessarily complex. It really seems to me as if I'm missing a basic function.

The simplest solution:
(apply <= mylist)
>= also works for reverse sorting

I would do a single pass over overlapping pairs of numbers and check they are <= (as you mention) because it is O(n), though you don't need to manually make pairs.
user> (partition-all 2 1 [1 2 3 4 5 6])
((1 2) (2 3) (3 4) (4 5) (5 6) (6))
user> (every? #(apply <= %) (partition-all 2 1 [1 2 3 4 6 5]))
false
user> (every? #(apply <= %) (partition-all 2 1 [1 2 3 4 5 6]))
true

You could sort the list and compare it to the original:
(= my-list (sort my-list))
Example:
> (def my-list (list 1 2 3 1 4 2 2 4))
#'sandbox3825/my-list
> (= my-list (sort my-list))
false
> (def my-list (list 1 2 3 4))
#'sandbox3825/my-list
> (= my-list (sort my-list))
true

Related

Single duplicate in a vector

Given a list of integers from 1 do 10 with size of 5, how do I check if there are only 2 same integers in the list?
For example
(check '(2 2 4 5 7))
yields yes, while
(check '(2 1 4 4 4))
or
(check '(1 2 3 4 5))
yields no
Here is a solution using frequencies to count occurrences and filter to count the number of values that occur only twice:
(defn only-one-pair? [coll]
(->> coll
frequencies ; map with counts of each value in coll
(filter #(= (second %) 2)) ; Keep values that have 2 occurrences
count ; number of unique values with only 2 occurrences
(= 1))) ; true if only one unique val in coll with 2 occurrences
Which gives:
user=> (only-one-pair? '(2 1 4 4 4))
false
user=> (only-one-pair? '(2 2 4 5 7))
true
user=> (only-one-pair? '(1 2 3 4 5))
false
Intermediate steps in the function to get a sense of how it works:
user=> (->> '(2 2 4 5 7) frequencies)
{2 2, 4 1, 5 1, 7 1}
user=> (->> '(2 2 4 5 7) frequencies (filter #(= (second %) 2)))
([2 2])
user=> (->> '(2 2 4 5 7) frequencies (filter #(= (second %) 2)) count)
1
Per a suggestion, the function could use a more descriptive name and it's also best practice to give predicate functions a ? at the end of it in Clojure. So maybe something like only-one-pair? is better than just check.
Christian Gonzalez's answer is elegant, and great if you are sure you are operating on a small input. However, it is eager: it forces the entire input list even when itcould in principle tell sooner that the result will be false. This is a problem if the list is very large, or if it is a lazy list whose elements are expensive to compute - try it on (list* 1 1 1 (range 1e9))! I therefore present below an alternative that short-circuits as soon as it finds a second duplicate:
(defn exactly-one-duplicate? [coll]
(loop [seen #{}
xs (seq coll)
seen-dupe false]
(if-not xs
seen-dupe
(let [x (first xs)]
(if (contains? seen x)
(and (not seen-dupe)
(recur seen (next xs) true))
(recur (conj seen x) (next xs) seen-dupe))))))
Naturally it is rather more cumbersome than the carefree approach, but I couldn't see a way to get this short-circuiting behavior without doing everything by hand. I would love to see an improvement that achieves the same result by combining higher-level functions.
(letfn [(check [xs] (->> xs distinct count (= (dec (count xs)))))]
(clojure.test/are [input output]
(= (check input) output)
[1 2 3 4 5] false
[1 2 1 4 5] true
[1 2 1 2 1] false))
but I like a shorter (but limited to exactly 5 item lists):
(check [xs] (->> xs distinct count (= 4)))
In answer to Alan Malloy's plea, here is a somewhat combinatory solution:
(defn check [coll]
(let [accums (reductions conj #{} coll)]
(->> (map contains? accums coll)
(filter identity)
(= (list true)))))
This
creates a lazy sequence of the accumulating set;
tests it against each corresponding new element;
filters for the true cases - those where the element is already present;
tests whether there is exactly one of them.
It is lazy, but does duplicate the business of scanning the given collection. I tried it on Alan Malloy's example:
=> (check (list* 1 1 1 (range 1e9)))
false
This returns instantly. Extending the range makes no difference:
=> (check (list* 1 1 1 (range 1e20)))
false
... also returns instantly.
Edited to accept Alan Malloy's suggested simplification, which I have had to modify to avoid what appears to be a bug in Clojure 1.10.0.
you can do something like this
(defn check [my-list]
(not (empty? (filter (fn[[k v]] (= v 2)) (frequencies my-list)))))
(check '(2 4 5 7))
(check '(2 2 4 5 7))
Similar to others using frequencies - just apply twice
(-> coll
frequencies
vals
frequencies
(get 2)
(= 1))
Positive case:
(def coll '(2 2 4 5 7))
frequencies=> {2 2, 4 1, 5 1, 7 1}
vals=> (2 1 1 1)
frequencies=> {2 1, 1 3}
(get (frequencies #) 2)=> 1
Negative case:
(def coll '(2 1 4 4 4))
frequencies=> {2 1, 1 1, 4 3}
vals=> (1 1 3)
frequencies=> {1 2, 3 1}
(get (frequencies #) 2)=> nil

Drop function in clojure

Given the following function, I could not understand what map function is receiving as second parameter.
(def tails
(fn [seq]
(map drop
(range (inc (count seq)))
(repeat (inc (count seq)) seq))))
Given that seq is (list 1 2 3)
The line:
(range (inc (count seq)))
Will produce ((1 2 3) (1 2 3) (1 2 3))
And the line:
(range (inc (count seq)))
Will produce (0 1 2 3)
So, what is receiving the map function as second parameter?
The second parameter is seq repeated as many times as its length + 1, so you can drop 0 to length elements from it.
For '(1 2 3), you get
(map drop '(0 1 2 3) (repeat 4 '( 1 2 3)))
which (when realized) will become the equivalent of
(list (drop 0 '(1 2 3)) (drop 1 '(1 2 3)) (drop 2 '(1 2 3)) (drop 3 '(1 2 3)))
which evaluates to
((1 2 3) (2 3) (3) ())

How to move first list item to the end?

For given list:
(1 2 3 4)
I'd like to get as output:
(2 3 4 1)
Code I came up with looks like this:
(flatten (cons (rest l) (list (first l))))
However my feeling is, that I overcomplicated this. Any other ideas?
You don't need to flatten a cons, just use concat.
Here is an example:
(let [fruit ["apple" "orange" "grapes" "bananas"]]
(concat (rest fruit) [(first fruit)])
Developing #stonemetal's hint, we can quickly and lazily rotate a vector thus:
(defn rotate [v n]
(let [cv (count v), n (mod n cv)]
(concat (subvec v n cv) (subvec v 0 n))))
It works in either direction:
(map #(rotate (vec (range 5)) %) (range -2 8))
;((3 4 0 1 2)
; (4 0 1 2 3)
; (0 1 2 3 4)
; (1 2 3 4 0)
; (2 3 4 0 1)
; (3 4 0 1 2)
; ...
; (2 3 4 0 1))
So to rotate the first in a sequence to the end:
(rotate (vec (range 1 5)) 1)
You can also use destructuring (either on the function arguments or in a let binding).
(let [[h & tail] '(1 2 3 4)]
(concat tail (list h))) ;=> (1 2 3 4)

Clojure - how to do reductions function but drop state?

If I use the reductions function like so:
(reductions + [1 2 3 4 5])
Then I get
(1 3 6 10 15)
Which is great - but I'd like to apply a binary function in the same way without the state being carried forward - something like
(magic-hof + [1 2 3 4 5])
leads to
(1 3 5 7 9)
ie it returns the operation applied to the first pair, then steps 1 to the next pair.
Can someone tell me the higher-order function I'm looking for? (Something like reductions)
This is my (non-working) go at it:
(defn thisfunc [a b] [(+ a b) b])
(reduce thisfunc [1 2 3 4 5])
You can do it with map:
(map f coll (rest coll))
And if you want a function:
(defn map-pairwise [f coll]
(map f coll (rest coll)))
And if you really need the first element to remain untouched (thanx to juan.facorro's comment):
(defn magic-hof [f [x & xs :as s]]
(cons x (map f s xs)))
partition will group your seq:
user> (->> [1 2 3 4 5] (partition 2 1) (map #(apply + %)) (cons 1))
(1 3 5 7 9)
So, you want to apply a function to subsequent pairs of elements?
(defn pairwise-apply
[f sq]
(when (seq sq)
(->> (map f sq (next sq))
(cons (first sq)))))
Let's try it:
(pairwise-apply + (range 1 6))
;; => (1 3 5 7 9)
This is sufficient:
(#(map + (cons 0 %) %) [1 2 3 4 5])
;; => (1 3 5 7 9)

Sliding window over seq

In Clojure, what would be the nicest way to have a sliding window over a (finite, not too large) seq? Should I just use drop and take and keep track of the current index or is there a nicer way I'm missing?
I think that partition with step 1 does it:
user=> (partition 3 1 [3 1 4 1 5 9])
((3 1 4) (1 4 1) (4 1 5) (1 5 9))
If you want to operate on the windows, it can also be convenient to do this with map:
user=> (def a [3 1 4 1 5 9])
user=> (map (partial apply +) (partition 3 1 a))
(8 6 10 15)
user=> (map + a (next a) (nnext a))
(8 6 10 15)
I didn't know partition could do this so I implemented it this way
(defn sliding-window [seq length]
(loop [result ()
remaining seq]
(let [chunk (take length remaining)]
(if (< (count chunk) length)
(reverse result)
(recur (cons chunk result) (rest remaining))))))