Single duplicate in a vector - clojure

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

Related

Clojure manually find nth element in a sequence

I am a newbie to clojure (and functional programming for that matter) and I was trying to do some basic problems. I was trying to find the nth element in a sequence without recursion.
so something like
(my-nth '(1 2 3 4) 2) => 3
I had a hard time looping through the list and returning when i found the nth element. I tried a bunch of different ways and the code that I ended up with is
(defn sdsu-nth
[input-list n]
(loop [cnt n tmp-list input-list]
(if (zero? cnt)
(first tmp-list)
(recur (dec cnt) (pop tmp-list)))))
This gives me an exception which says "cant pop from empty list"
I dont need code, but if someone could point me in the right direction it would really help!
You are using the function pop, which has different behavior for different data structures.
user> (pop '(0 1 2 3 4))
(1 2 3 4)
user> (pop [0 1 2 3 4])
[0 1 2 3]
user> (pop (map identity '(0 1 2 3 4)))
ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IPersistentStack clojure.lang.RT.pop (RT.java:640)
Furthermore, you are mixing calls to pop with calls to first. If iterating, use peek/pop or first/rest as pairs, mixing the two can lead to unexpected results. first / rest are the lowest common denominator, if you want to generalize over various sequential types, use those, and they will coerce the sequence to work if they can.
user> (first "hello")
\h
user> (first #{0 1 2 3 4})
0
user> (first {:a 0 :b 1 :c 2})
[:c 2]
With your function, replacing pop with rest, we get the expected results:
user> (defn sdsu-nth
[input-list n]
(loop [cnt n tmp-list input-list]
(if (zero? cnt)
(first tmp-list)
(recur (dec cnt) (rest tmp-list)))))
#'user/sdsu-nth
user> (sdsu-nth (map identity '(0 1 2 3 4)) 2)
2
user> (sdsu-nth [0 1 2 3 4] 2)
2
user> (sdsu-nth '(0 1 2 3 4) 2)
2
user> (sdsu-nth "01234" 2)
\2
given a list as list_nums, take up to n + 1 then from that return the last element which is nth.
(fn [list_nums n] (last (take (inc n) list_nums)))
and alternatively:
#(last (take (inc %2) %1))
proof:
(= (#(last (take (inc %2) %1)) '(4 5 6 7) 2) 6) ;; => true
What you would really want to do is use the built-in nth function as it does exactly what you're asking:
http://clojuredocs.org/clojure_core/clojure.core/nth
However, since you're learning this is still a good exercise. Your code actually works for me. Make sure you're giving it a list and not a vector -- pop does something different with vectors (it returns the vector without the last item rather than the first -- see here).
Your code works fine for lists if supplied index is not equal or greater then length of sequence (you've implemented zero indexed nth). You get this error when tmp-list gets empty before your cnt gets to the zero.
It does not work so well with vectors:
user> (sdsu-nth [1 2 3 4] 2)
;; => 1
user> (sdsu-nth [10 2 3 4] 2)
;; => 10
it seems to return 0 element for every supplied index. As noisesmith noticed it happens because pop works differently for vectors because of their internal structure. For vectors pop will remove elements form the end, and then first returns first value of any vector.
How to fix: use rest instead of pop, to remove differences in behavior of your function when applied to lists and vectors.
(fn [xs n]
(if (= n 0)
(first xs)
(recur (rest xs) (dec n))))
One more way that I thought of doing this and making it truly non recursive (ie without for/recur) is
(defn sdsu-nth
[input-list n]
(if (zero? (count input-list))
(throw (Exception. "IndexOutOfBoundsException"))
(if (>= n (count input-list))
(throw (Exception. "IndexOutOfBoundsException"))
(if (neg? n)
(throw (Exception. "IndexOutOfBoundsException"))
(last (take (+ n 1) input-list))))))

Map with an accumulator in Clojure?

I want to map over a sequence in order but want to carry an accumulator value forward, like in a reduce.
Example use case: Take a vector and return a running total, each value multiplied by two.
(defn map-with-accumulator
"Map over input but with an accumulator. func accepts [value accumulator] and returns [new-value new-accumulator]."
[func accumulator collection]
(if (empty? collection)
nil
(let [[this-value new-accumulator] (func (first collection) accumulator)]
(cons this-value (map-with-accumulator func new-accumulator (rest collection))))))
(defn double-running-sum
[value accumulator]
[(* 2 (+ value accumulator)) (+ value accumulator)])
Which gives
(prn (pr-str (map-with-accumulator double-running-sum 0 [1 2 3 4 5])))
>>> (2 6 12 20 30)
Another example to illustrate the generality, print running sum as stars and the original number. A slightly convoluted example, but demonstrates that I need to keep the running accumulator in the map function:
(defn stars [n] (apply str (take n (repeat \*))))
(defn stars-sum [value accumulator]
[[(stars (+ value accumulator)) value] (+ value accumulator)])
(prn (pr-str (map-with-accumulator stars-sum 0 [1 2 3 4 5])))
>>> (["*" 1] ["***" 2] ["******" 3] ["**********" 4] ["***************" 5])
This works fine, but I would expect this to be a common pattern, and for some kind of map-with-accumulator to exist in core. Does it?
You should look into reductions. For this specific case:
(reductions #(+ % (* 2 %2)) 2 (range 2 6))
produces
(2 6 12 20 30)
The general solution
The common pattern of a mapping that can depend on both an item and the accumulating sum of a sequence is captured by the function
(defn map-sigma [f s] (map f s (sigma s)))
where
(def sigma (partial reductions +))
... returns the sequence of accumulating sums of a sequence:
(sigma (repeat 12 1))
; (1 2 3 4 5 6 7 8 9 10 11 12)
(sigma [1 2 3 4 5])
; (1 3 6 10 15)
In the definition of map-sigma, f is a function of two arguments, the item followed by the accumulator.
The examples
In these terms, the first example can be expressed
(map-sigma (fn [_ x] (* 2 x)) [1 2 3 4 5])
; (2 6 12 20 30)
In this case, the mapping function ignores the item and depends only on the accumulator.
The second can be expressed
(map-sigma #(vector (stars %2) %1) [1 2 3 4 5])
; (["*" 1] ["***" 2] ["******" 3] ["**********" 4] ["***************" 5])
... where the mapping function depends on both the item and the accumulator.
There is no standard function like map-sigma.
General conclusions
Just because a pattern of computation is common does not imply that
it merits or requires its own standard function.
Lazy sequences and the sequence library are powerful enough to tease
apart many problems into clear function compositions.
Rewritten to be specific to the question posed.
Edited to accommodate the changed second example.
Reductions is the way to go as Diego mentioned however to your specific problem the following works
(map #(* % (inc %)) [1 2 3 4 5])
As mentioned you could use reductions:
(defn map-with-accumulator [f init-value collection]
(map first (reductions (fn [[_ accumulator] next-elem]
(f next-elem accumulator))
(f (first collection) init-value)
(rest collection))))
=> (map-with-accumulator double-running-sum 0 [1 2 3 4 5])
(2 6 12 20 30)
=> (map-with-accumulator stars-sum 0 [1 2 3 4 5])
("*" "***" "******" "**********" "***************")
It's only in case you want to keep the original requirements. Otherwise I'd prefer to decompose f into two separate functions and use Thumbnail's approach.

How to verify if a list is sorted?

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

Overhand Shuffle with Clojure - almost

I'm trying to implement a Overhand Shuffle in Clojure as a bit of a learning exercise
So I've got this code...
(defn overhand [cards]
(let [ card_count (count cards)
_new_cards '()
_rand_ceiling (if (> card_count 4) (int (* 0.2 card_count)) 1)]
(take card_count
(reduce into (mapcat
(fn [c]
(-> (inc (rand-int _rand_ceiling))
(take cards)
(cons _new_cards)))
cards)))))
It is very close to doing what I want, but it is repeatedly taking the first (random) N number of cards off the front, but I want it to progress through the list...
calling as
(overhand [1 2 3 4 5 6 7 8 9])
instead of ending up with
(1 2 3 1 2 1 2 3 4)
I want to end up with
(7 8 9 5 6 1 2 3 4)
Also, as a side note this feels like a really ugly way to indent/organize this function, is there a more obvious way?
this function is creating a list of lists, transforming each of them, and cating them back together. the problem it that it is pulling from the same thing every time and appending to a fixed value. essentially it is running the same operation every time and so it is repeating the output over with out progressing thgough the list. If you break the problem down differently and split the creation of random sized chunks from the stringing them together it gets a bit easier to see how to make it work correctly.
some ways to split the sequence:
(defn random-partitions [cards]
(let [card_count (count cards)
rand_ceiling (if (> card_count 4) (inc (int (* 0.2 card_count))) 1)]
(partition-by (ƒ [_](= 0 (rand-int rand_ceiling))) cards)))
to keep the partitions less than length four
(defn random-partitions [cards]
(let [[h t] (split-at (inc (rand-int 4)) cards)]
(when (not-empty h) (lazy-seq (cons h (random-partition t))))))
or to keep the partitions at the sizes in your original question
(defn random-partitions [cards]
(let [card_count (count cards)
rand_ceiling (if (> card_count 4) (inc (int (* 0.2 card_count))) 1)
[h t] (split-at (inc (rand-int rand_ceiling)) cards)]
(when (not-empty h) (lazy-seq (cons h (random-partition t))))))
(random-partitions [1 2 3 4 5 6 7 8 9 10])
((1 2 3 4) (5) (6 7 8 9) (10))
this can also be written without directly using lazy-seq:
(defn random-partitions [cards]
(->> [[] cards]
(iterate
(ƒ [[h t]]
(split-at (inc (rand-int 4)) t)))
rest ;iterate returns its input as the first argument, drop it.
(map first)
(take-while not-empty)))
which can then be reduced back into a single sequence:
(reduce into (random-partitions [1 2 3 4 5 6 7 8 9 10]))
(10 9 8 7 6 5 4 3 1 2)
if you reverse the arguments to into it looks like a much better shuffle
(reduce #(into %2 %1) (random-partitions [1 2 3 4 5 6 7 8 9 10]))
(8 7 1 2 3 4 5 6 9 10)
Answering your indentation question, you could refactor your function. For instance, pull out the lambda expression from mapcat, defn it, then use its name in the call to mapcat. You'll not only help with the indentation, but your mapcat will be clearer.
For instance, here's your original program, refactored. Please note that issues with your program have not been corrected, I'm just showing an example of refactoring to improve the layout:
(defn overhand [cards]
(let [ card_count (count cards)
_new_cards '()
_rand_ceiling (if (> card_count 4) (int (* 0.2 card_count)) 1)]
(defn f [c]
(-> (inc (rand-int _rand_ceiling))
(take cards)
(cons _new_cards)))
(take card_count (reduce into (mapcat f cards)))))
You can apply these principles to your fixed code.
A great deal of indentation issues can be resolved by simply factoring out complex expressions. It also helps readability in general.
A better way to organise the function is to separate the shuffling action from the random selection of splitting points that drive it. Then we can test the shuffler with predictable splitters.
The shuffling action can be expressed as
(defn shuffle [deck splitter]
(if (empty? deck)
()
(let [[taken left] (split-at (splitter (count deck)) deck)]
(concat (shuffle left splitter) taken))))
where
deck is the sequence to be shuffled
splitter is a function that chooses where to split deck, given its
size.
We can test shuffle for some simple splitters:
=> (shuffle (range 10) (constantly 3))
(9 6 7 8 3 4 5 0 1 2)
=> (shuffle (range 10) (constantly 2))
(8 9 6 7 4 5 2 3 0 1)
=> (shuffle (range 10) (constantly 1))
(9 8 7 6 5 4 3 2 1 0)
It works.
Now let's look at the way you choose your splitting point. We can illustrate your choice of _rand_ceiling thus:
=> (map
(fn [card_count] (if (> card_count 4) (int (* 0.2 card_count)) 1))
(range 20))
(1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3)
This implies that you will take just one or two cards from any deck of less than ten. By the way, a simpler way to express the function is
(fn [card_count] (max (quot card_count 5) 1))
So we can express your splitter function as
(fn [card_count] (inc (rand-int (max (quot card_count 5) 1))))
So the shuffler we want is
(defn overhand [deck]
(let [splitter (fn [card_count] (inc (rand-int (max (quot card_count 5) 1))))]
(shuffle deck splitter)))

clojure map over sequence of pairs

(def tmp = [ 1 2 3 9 4 8])
I'm trying to create pairs of 2, then for each pair, subtract the second number from the first.
desired result: (1 6 4)
Here is what I was trying:
(map #(apply - %2 %1) (partition 2 tmp))
how can I do this?
Partition produces a sequence of sequences so the function you map over them needs to expect a sequence of two items. There are several ways to express this:
(def tmp [ 1 2 3 9 4 8])
user> (map #(- (second %) (first %)) (partition-all 2 tmp ))
(1 6 4)
user> (map #(apply - (reverse %)) (partition-all 2 tmp ))
(1 6 4)
user> (map (fn [[small large]] (- large small)) (partition-all 2 tmp ))
(1 6 4)
The version using apply is different because it will still "work" on odd length lists:
user> (map #(apply - (reverse %)) (partition-all 2 [1 2 3 4 5 6 7] ))
(1 1 1 -7)
The others will crash on invalid input, which you may prefer.
Here's a solution using reduce
(reduce #(conj %1 (apply - (reverse %2))) [] (partition-all 2 [1 2 3 9 4 8]))
=> [1 6 4]
I wonder why this solution was overlooked...
Since switching the order of subtraction is simply the negative of the original subtraction, (a-b=-(b-a)),
the solution becomes more efficient (only in this particular case!!)
(map #(- (apply - %)) (partition-all 2 [1 2 3 9 4 8]))
Pedagogically, Arthur's solution is correct. This is just a solution that is more suited the specfic question.