Clojure: number of consecutive repetition items - clojure

I need a function to calculate the number of consecutive equal entries in a sequence. For example, (consecutive "abcdefg") should return 0, while (consecutive "aabcdddefg") should return 3.
Is the way i wrote it idiomatic or could it be improved?
(defn consecutive [p]
(second (reduce
#(vector %2
(if (= (first %1) %2)
(inc (second %1))
(second %1)))
[nil 0]
p)))

I think that (consecutive "abcdefg") should return 1, not 0.
Here's a simple implementation that achieves this:
(defn consecutive [s]
(apply max (map count (partition-by identity s))))

user> (defn consecutive [s] (->> s (partition-by identity) (reduce #(+ % (dec (count %2))) 0)))
#'user/consecutive
user> (consecutive "abcdefg")
0
user> (consecutive "aabcdddefg")
3
I prefer the (partition-by identity) idiom when some consecutive sequences are required.

try this.
(defn consecutive [string]
(let [n (apply max (map count (partition-by identity string)))]
(if (= n 1) 0 n)))
it's common pattern

Related

clojure performance on badly performing code

I have completed this problem on hackerrank and my solution passes most test cases but it is not fast enough for 4 out of the 11 test cases.
My solution looks like this:
(ns scratch.core
(require [clojure.string :as str :only (split-lines join split)]))
(defn ascii [char]
(int (.charAt (str char) 0)))
(defn process [text]
(let [parts (split-at (int (Math/floor (/ (count text) 2))) text)
left (first parts)
right (if (> (count (last parts)) (count (first parts)))
(rest (last parts))
(last parts))]
(reduce (fn [acc i]
(let [a (ascii (nth left i))
b (ascii (nth (reverse right) i))]
(if (> a b)
(+ acc (- a b))
(+ acc (- b a))))
) 0 (range (count left)))))
(defn print-result [[x & xs]]
(prn x)
(if (seq xs)
(recur xs)))
(let [input (slurp "/Users/paulcowan/Downloads/input10.txt")
inputs (str/split-lines input)
length (read-string (first inputs))
texts (rest inputs)]
(time (print-result (map process texts))))
Can anyone give me any advice about what I should look at to make this faster?
Would using recursion instead of reduce be faster or maybe this line is expensive:
right (if (> (count (last parts)) (count (first parts)))
(rest (last parts))
(last parts))
Because I am getting a count twice.
You are redundantly calling reverse on every iteration of the reduce:
user=> (let [c [1 2 3]
noisey-reverse #(doto (reverse %) println)]
(reduce (fn [acc e] (conj acc (noisey-reverse c) e))
[]
[:a :b :c]))
(3 2 1)
(3 2 1)
(3 2 1)
[(3 2 1) :a (3 2 1) :b (3 2 1) :c]
The reversed value could be calculated inside the containing let, and would then only need to be calculated once.
Also, due to the way your parts is defined, you are doing linear time lookups with each call to nth. It would be better to put parts in a vector and do indexed lookup. In fact you wouldn't need a reversed parts, and could do arithmetic based on the count of the vector to find the item to look up.

insert-sort with reduce clojure

I have function
(defn goneSeq [inseq uptil]
(loop [counter 0 newSeq [] orginSeq inseq]
(if (== counter uptil)
newSeq
(recur (inc counter) (conj newSeq (first orginSeq)) (rest orginSeq)))))
(defn insert [sorted-seq n]
(loop [currentSeq sorted-seq counter 0]
(cond (empty? currentSeq) (concat sorted-seq (vector n))
(<= n (first currentSeq)) (concat (goneSeq sorted-seq counter) (vector n) currentSeq)
:else (recur (rest currentSeq) (inc counter)))))
that takes in a sorted-sequence and insert the number n at its appropriate position for example: (insert [1 3 4] 2) returns [1 2 3 4].
Now I want to use this function with reduce to sort a given sequence so something like:
(reduce (insert seq n) givenSeq)
What is thr correct way to achieve this?
If the function works for inserting a single value, then this would work:
(reduce insert [] givenSeq)
for example:
user> (reduce insert [] [0 1 2 30.5 0.88 2.2])
(0 0.88 1 2 2.2 30.5)
Also, it should be noted that sort and sort-by are built in and are better than most hand-rolled solutions.
May I suggest some simpler ways to do insert:
A slowish lazy way is
(defn insert [s x]
(let [[fore aft] (split-with #(> x %) s)]
(concat fore (cons x aft))))
A faster eager way is
(defn insert [coll x]
(loop [fore [], coll coll]
(if (and (seq coll) (> x (first coll)))
(recur (conj fore x) (rest coll))
(concat fore (cons x coll)))))
By the way, you had better put your defns in bottom-up order, if possible. Use declare if there is mutual recursion. You had me thinking your solution did not compile.

Generating binary numbers of n digits in clojure

I'd like to generate binary numbers of n digits from 0 to 2^n-1. For example of 3 digits, "000", "001", "010", ..., "111" (0 to 7 in decimal). The way I used is to use java.lang.Integer.toBinaryString() method and add zeros if necessary like the following:
(defn pad-zero [s n]
(str (reduce str (repeat (- n (count s)) "0")) s))
(defn binary-permutation [n]
(map (fn [s] (pad-zero s n))
(map #(Integer/toBinaryString %) (range 0 (Math/pow 2 n)))))
With this code, I can generate what I want like this. For 3 digits:
(binary-permutation 3)
=> ("000" "001" "010" "011" "100" "101" "110" "111")
But this codes look a little verbose.
Aren't there any ways better or more clojure way to do this?
You can simplify the formatting using cl-format from clojure.pprint:
(defn binary-permutation [n]
(map (partial cl-format nil "~v,'0B" n) (range 0 (Math/pow 2 n))))
You may also be interested to know that (Math/pow 2 n) is equivalent to (bit-shift-left 1 n).
Another way to express this would be in term of selections from clojure.math.combinatorics:
(defn binary-permutation [n]
(map (partial apply str) (selections [0 1] n)))
(defn binary-permutation [n]
(for [x (range (Math/pow 2 n))]
(apply str (reverse (take n (map #(bit-and 1 %) (iterate #(bit-shift-right % 1) x)))))))
(defn pad-zero [s n]
(apply str (take-last n (concat (repeat n \0) s))))

Find index of an element matching a predicate in Clojure?

With Clojure, how do I find the first index with a positive value in this vector [-1 0 3 7 9]?
I know you can get the first result of something rather elegantly with first and filter:
(first (filter pos? [-1 0 99 100 101]))
This code returns the value 99. The answer I want is the index which is 2.
Using keep-indexed you can get a sequence of indices for which a predicate is satisfied:
(defn indices [pred coll]
(keep-indexed #(when (pred %2) %1) coll))
With this simple function you'll solve your problem with the expression
user=> (first (indices pos? [-1 0 99 100 101]))
2
Note that, due to the lazyness of keep-indexed (and indices), the entire sequence need not be realized so no extraneous calculations are performed.
(defn first-pos [x]
(loop [arr x n 0]
(if (pos? (first arr))
n
(recur (next arr) (inc n)))))
This is a good example of using functional programming's powerful tail recursion.
(first (filter #(not (nil? %)) (map #(when (pos? %1) %2) [-1 1 0 99 100 101] (range))))
Map can take one or more collections and return one list,put condition on map,and filter nil.
(defn pred-idx [pred [idx hist] cur]
(if (pred cur)
[(inc idx) (conj hist idx)]
[(inc idx) hist]))
(defn idx-filter [pred col]
(second (reduce (partial pred-idx pred) [0 []] col)))
(first (idx-filter pos? [-1 0 99 100 101]))
2
Not sure if this is better, but it works. I think it forces evaluation of the entire sequence though, and if you need all indices that would be better. The correct thing to do is probably turn it into a lazy sequence somehow, but I'm done for the evening.
I'm a little late to the party, but I prefer:
(defn index-of-pred
[pred coll]
(ffirst (filter (comp pred second) (map-indexed list coll))))
;; example usage
(index-of-pred pos? [-1 -2 -5 0 3 4 1 -100])
;=> 4
Try this:
(defn first-index
([pred coll] (first-index coll pred 0))
([pred coll idx]
(cond (= coll '()) -1
(pred (first coll)) idx
:else (recur pred (rest coll) (inc idx)))))
And use it like this:
(defn is-pos? [x]
(> x 0))
(first-index is-pos? [-1 0 3 7 9])
It returns the zero-based index of the first element that satisfies the predicate (is-pos? in the example), or -1 if no element matches the predicate.

Applying multiple filters to a collection in a thrush in Clojure

The following code
(let [coll [1 2 3 4 5]
filters [#(> % 1) #(< % 5)]]
(->> coll
(filter (first filters))
(filter (second filters))))
Gives me
(2 3 4)
Which is great, but how do I apply all the filters in coll without having to explicitly name them?
There may be totally better ways of doing this, but ideally I'd like to know an expression that can replace (filter (first filters)) (filter (second filters)) above.
Thanks!
Clojure 1.3 has a new every-pred function, which you could use thusly:
(filter (apply every-pred filters) coll)
This should work :-
(let [coll [1 2 3 4 5]
filters [#(> % 1) #(< % 5)]]
(filter (fn [x] (every? #(% x) filters)) coll)
)
I can't say I'm very proud of the following, but at least it works and allows for infinite filters:
(seq
(reduce #(clojure.set/intersection
(set %1)
(set %2)) (map #(filter % coll) filters)))
If you can use sets in place of seqs it would simplify the above code as follows:
(reduce clojure.set/intersection (map #(filter % coll) filters))
(let [coll [1 2 3 4 5]
filters [#(> % 1) #(< % 5)]]
(reduce (fn [c f] (filter f c)) coll filters))