Beginner's clojure attempt to hackkerrank problem timing out - clojure

I'm attempting the following problem on hackerrank:
https://www.hackerrank.com/challenges/counting-valleys
but unfortunately my following clojure code is timing out on many test cases, and I don't know what makes it so inefficient. Please be lenient. I only have in total 2 hours of total clojure experience.
(require '[clojure.string :as str])
; Complete the countingValleys function below.
(defn countingValleys [n s]
(do
(def running 0)
(defn counter [elem]
(do
(cond
(= elem "D") (def running (+ running 1))
(= elem "U")(def running (- running 1))
)
running
)
)
(def valley-num 0)
(defn valley-count [a b]
(do
(if (and (= a "U") (= b 0))
(def valley-num (+ valley-num 1)))
)
)
(def heights (for [elem s] (counter elem)))
(doseq [[i j] (map vector s heights)]
(valley-count i j))
valley-num
)
)
(def fptr (get (System/getenv) "OUTPUT_PATH"))
(def n (Integer/parseInt (clojure.string/trim (read-line))))
(def s (read-line))
(def result (countingValleys n (str/split s #"")))
(spit fptr (str result "\n") :append true)
Dead easy python implementation of the same logic that took 5 minutes and passes all test cases:
def countingValleys(n, s):
list = []
for i in range(len(s)):
d = 0
if s[i] == "D":
d = 1
elif s[i] == "U":
d = -1
if len(list) == 0:
list.append(d)
else:
list.append(list[-1] + d)
num = 0
for i in range(len(s)):
if s[i] == "U" and list[i] == 0:
num += 1
return num

So I figured it out. The inefficiency was in this line:
(doseq [[i j] (map vector s heights)]
(valley-count i j))
Which can be replaced with:
(doall (map valley-count s heights))
and then all tests pass.

The slowness of your code is the least of its problems. The tools you ought to be employing are
pure functions,
the sequence library,
and, for speed, the prospect of transducers.
I like your underlying algorithm: count the cases where an up movement takes you to sea level.
We can express it idiomatically thus:
(defn countingValleys [n s]
(let [counter {\D 1, \U -1}
heights (reductions + (map counter s))
s-heights (map vector s heights)
valley-num (count (filter #{[\U 0]} s-heights))]
valley-num))
... or, using the ->> threading macro ...
(defn countingValleys [_ s]
(->> s
(map {\D 1, \U -1})
(reductions +)
(map vector s)
(filter #{[\U 0]})
(count)))
These are clearer and faster than yours.
It seems that you and HackerRank are actually using ClojureScript. Your use of "U" as an element of a string won't work in Clojure proper: you have to use the character \U.

Those of us who are JavaScript(Node JS) developers, my solution here works perfectly
// Complete the countingValleys function below.
function countingValleys(n, s) {
const min = 2;
const max = 1000000;
let valleys = 0;
let isInValley;
s = (typeof s === 'string') ? s.split('') : s;
if (s.length >= min && s.length <= max &&
n === parseInt(n, 0) &&
n >= min &&
n <= max &&
n === s.length) {
s.map(steps => ((steps === "U") ? 1 : -1))
.reduce((prev, next) => {
if (prev < 0 && !isInValley) {
isInValley = true;
}
if ((prev + next) === 0 && isInValley) {
valleys++;
isInValley = false;
}
return prev + next;
});
}
return valleys;
}

Related

Rewriting java if statements in clojure syntax

I have a set of recursive if statements written in Java and I tried taking it to clojure syntax but got the ArrayOutOfBound error. The functions accepts row = 0, col = 0 and a multidimensional array of characters.
This is the Java Code:
public static boolean solveMaze(int r, int c, char[][] maze) {
//check for boundaries
if(r < 0 || c < 0 || r >= maze.length || c >= maze[0].length)
return false;
//base case, did i reach the finish?
if(maze[r][c] == '#')
return true;
//check if I'm at a valid point
if(maze[r][c] != '-')
//I have hit a wall, not a valid solution
return false;
//must be on a path, may be the right path
//leave a bread crumb
maze[r][c] = '!';
//check above
if(solveMaze(r-1,c, maze)) {
maze[r][c] = '+';
return true;
}
//check below
if(solveMaze(r+1,c, maze)) {
maze[r][c] = '+';
return true;
}
//check left
if(solveMaze(r,c-1, maze)) {
maze[r][c] = '+';
return true;
}
//check right
if(solveMaze(r,c+1, maze)) {
maze[r][c] = '+';
return true;
}
//if I reach this point...
return false;
}
This is my code in clojure that provides the Index out of bound error:
(defn solveMaze [r c m]
(def tt true)
;(def che false)
;check to verify boundaries
(if (or (or (or (< r 0) (< c 0)) (>= r (count m))) (>= c (count (str (m 0)))))
false
true
)
;Check to know if the # symbol has been found
(if (= (get-in m[r c]) "#")
true
false
)
;Checking if current index is a valid one
(if (not= (get-in m[r c]) "-")
;Wall hit
false
true
)
;found a path, leave a breadcrumb
(def temp_map (assoc-in m[r c] "!"))
;Check North
(if (= (solveMaze (dec r) c m) true)
(def temp_map (assoc-in m [r c] "+"))
true
;false
)
;Check South
(if (= (solveMaze (inc r) c m) true)
(def temp_map (assoc-in m[r c] "+"))
true
;false
)
;Check East
(if (= (solveMaze r (dec c) m) true)
(def temp_map (assoc-in m[r c] "+"))
true
;false
)
;Check West
(if (= (solveMaze r (inc c) m) true)
(def temp_map (assoc-in m[r c] "+"))
true
;false
)
;If code gets here
(= tt false)
)
Please is there something I am doing wrongly??? I have tried several if constructs using clojure but it doesn't work.
You need to read up on the basics of Clojure:
Brave Clojure (online & book)
Getting Clojure book
Clojure CheatSheet book
Use a cond to solve this instead of if. The way the code executes now is that first if is evaluated and then it goes to the next line to execute rest of code. With cond, if an expression is evaluated to be true, it returns the value and won't evaluate other expressions.
Refer :https://clojuredocs.org/clojure.core/cond

Clojure: nth not supported on this type: Boolean"

I am trying to implement the dining philosopher example in clojure.
For some reasons my program always dies with an exception saying
"java.lang.UnsupportedOperationException: nth not supported on this
type: Boolean"
I can't understand this error message since I already tried to get boolean values from a list which worked perfectly with nth
I guess the error happens in the if statement in the function philosopher-thread
Console Prints:
3 is thinking
1 is thinking
4 is thinking
0 is thinking
2 is thinking
0 after sleep
0 after think
0 swap
0 is eating
3 after sleep
3 after think
Code:
(ns dining-philosphers.core
(:gen-class))
(defn think [n]
(println (str n " is thinking"))
(Thread/sleep (rand 1000))
(println (str n " after sleep"))
)
(defn eat [n]
(println (str n " is eating"))
(Thread/sleep (rand 1000))
)
(def isEating (atom '(false false false false false)))
(defn philosopher-thread [n]
(Thread. #(
(while true (do
(think n)
(println (str n " after think"))
(if (or (nth #isEating (mod (- n 1) 5)) (nth #isEating (mod (+ n 1) 5)))
(println "is waiting for neighbour")
(
do
(println (str n " swap"))
(swap! isEating (fn [l] assoc l n true))
(eat n)
(swap! isEating (fn [l] assoc l n true))
)
)
)
)
)
)
)
(defn -main [& args]
(let [threads (map philosopher-thread (range 5))]
(doseq [thread threads] (.start thread))
(doseq [thread threads] (.join thread))))
You're missing some parens here:
(swap! isEating (fn [l] assoc l n true))
should be
(swap! isEating (fn [l] (assoc l n true)))
The first will evaluate assoc, l, n and true in order, and return the value of the last expression (true)
There is still a problem, which is that you can't assoc onto a list. I suggest using a vector instead:
(def isEating (atom [false false false false false]))

Ways to quickly update an element of a matrix in Incanter, Clojure?

Suppose I have a 3x3 matrix
(def myMatrix (matrix (range 9) 3))
; A 3x3 matrix
; -------------
; 0.00e+00 1.00e+00 2.00e+00
; 3.00e+00 4.00e+00 5.00e+00
; 6.00e+00 7.00e+00 8.00e+00
I can use $ to get an element, say 2nd row 1st column
($ 1 0 myMatrix) ; --> 3
Is there any API method to quickly update an element and then return a matrix? e.g.
(update-matrix-by-element 2 1 myMatrix 4)
; A 3x3 matrix
; -------------
; 0.00e+00 1.00e+00 2.00e+00
; 4.00e+00 4.00e+00 5.00e+00
; 6.00e+00 7.00e+00 8.00e+00
The closest API methods I can find are bind-rows and bind-columns, and my current version of function using these two methods is
;note i j starts from 1 rather than 0
(defn update-matrix-by-element [i j myMatrix value]
(if (or (> i (count (trans myMatrix))) (> j (count myMatrix)) (< i 1) (< j 1) (not (integer? i)) (not (integer? j)))
myMatrix
(let [n (count myMatrix)
m (count (trans myMatrix))
rangeFn #(if (== %1 %2) %1 (range %1 %2 ))
m1 (if (== (dec i) 0) []
($ (rangeFn 0 (dec i)) :all myMatrix))
m2 (if (== i m) []
($ (rangeFn i m) :all myMatrix))
matrixFn #(if (matrix? % ) % [ %])
newRow (if (== (dec j) 0)
(bind-columns [value] (matrixFn ($ (dec i) (rangeFn j n ) myMatrix)))
(if (== j n )
(bind-columns (matrixFn ($ (dec i) (rangeFn 0 (dec j) ) myMatrix)) [value] )
(bind-columns (matrixFn ($ (dec i) (rangeFn 0 (dec j) ) myMatrix)) [value] (matrixFn ($ (dec i) (rangeFn j n ) myMatrix))))
)
]
; (prn " m1 " m1 ) (prn " m2 " m2 ) (prn " newrow " newRow)
(bind-rows m1 newRow m2))))
If you mean "quickly" in the sense of performance, then you may probably to look at core.matrix which is designed to support fast mutable matrix operations.
Example using the vectorz-clj implementation for core.matrix:
(def M (matrix [[1 2] [3 4]]))
=> #<Matrix22 [[1.0,2.0][3.0,4.0]]>
(mset! M 0 0 10)
=> #<Matrix22 [[10.0,2.0][3.0,4.0]]>
(time (dotimes [i 1000000] (mset! M 0 0 i)))
"Elapsed time: 28.895842 msecs" ;; i.e. < 30ns per mset! operation
This will be much faster than anything which requires construction of a new mutable matrix, especially as the matrices get bigger / have higher dimensionality.
I'm working on making core.matrix integrate neatly with Incanter, so you should be able to use core.matrix matrices transparently within Incanter before too long.

Returning a value from a function after processing

How do i return a value from a function after doing some processing in clojure.
Code in Java
private int add() {
int i = 0;
if (i == 0) i++;
if (i == 1) i += 2;
else i += 3;
}
I have thought of using let but there are too many if statements hence i am unsure how do i return.
The simplest transliteration is to merely name new locals for each new value of i, like so:
(defn add []
(let [i 0
i' (if (= i 0) (inc i) i)
i'' (if (= i' 1)
(+ 2 i')
(+ 3 i'))]
i''))
All of these locals could have been named i, rather than calling them i', but I didn't want to confuse the issue of immutability: we are not modifying i in any way, just introducing a new named local bound to a new value.
The pattern of your code is:
if-else-expr(init-value) -> value1
if-else-expr(value1) -> value2
if-else-expr(value2) -> value3
if-else-expr...
It can be implemented in clojure as
(defn add []
(-> init-value
(#(if (expr1-1) (expr1-2) (expr1-3)))
(#(if (expr2-1) (expr2-2) (expr2-3)))
(#(if (expr3-1) (expr3-2) (expr3-3)))
...))
In your case:
(defn add []
(-> 0
(#(if (= % 0) (+ % 1) %))
(#(if (= % 1) (+ % 2) (+ % 3)))))

How do you replace Java nested for loops in Clojure?

I have created a very simple nested loop example and am struggling to write the equivalent Clojure code. I've been trying to do it by list comprehensions but cannot get the same answer. Any help appreciated.
public class Toy {
public static void main(String[] args) {
int maxMod = 0;
for (int i=0;i<1000;i++) {
for (int j=i;j<1000;j++) {
if ((i * j) % 13 == 0 && i % 7 == 0) maxMod = i * j;
}
}
System.out.println(maxMod);
}
}
Here's a list comprehension solution:
(last
(for [i (range 1000)
j (range 1000)
:let [n (* i j)]
:when (and (= (mod n 13) 0)
(= (mod i 7) 0))]
n))
In general, you want to use some sort of sequence operation (like dnolen's answer). However, if you need to do something that is not expressible in some combination of sequence functions, using the loop macro works as well. For this precise problem, dnolen's answer is better than anything using loop, but for illustrative purposes, here is how you would write it with loop.
(loop [i 0
max-mod 0]
(if (>= i 1000)
(println max-mod)
(recur (inc i)
(loop [j 0
max-mod max-mod]
(if (>= j 1000)
max-mod
(recur (inc j)
(if (and (= (mod (* i j) 13) 0)
(= (mod 1 7) 0))
(* i j)
max-mod)))))))
This is pretty much an exact translation of your given code. That said, this is obviously ugly, which is why a solution using for (or other similar functions) is preferred whenever possible.
List comprehensions create lists from other lists, but you want just a single value as result. You can create the input values (i and j) with a list comprehension, and then use reduce to get a single value from the list:
(reduce (fn [max-mod [i j]]
(if (and (zero? (mod (* i j) 13))
(zero? (mod i 7)))
(* i j)
max-mod))
0
(for [i (range 1000) j (range 1000)]
[i j]))