Rewriting java if statements in clojure syntax - clojure

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

Related

Beginner's clojure attempt to hackkerrank problem timing out

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;
}

clojure macro create || comparison?

I want to create an || comparison with Clojure like other languages.
(defmacro ||
[source & other]
`(loop [s# [~source ~#other]]
(println s#)
(let [fs# (first s#)]
(if fs#
fs#
(if (= (count s#) 1)
fs#
(recur (next s#)))))))
but this can't work. fs# value is quote data.
like this
(def a [1])
(defn b []
(println 11111))
(|| (get a 0) (b))
I want the result to be 1, this is (get a 0) but the result is (get a 0) this is Expression, not a var. How do I create an || macro?
Clojure's equivalent of || is the macro or . You can view its implementation here.
If you want to use the symbol ||, you can just alias the or macro:
(def #^{:macro true} || #'or)
You can then use either:
(or (get a 0) (b))
or
(|| (get a 0) (b))
What's your expected result, (get a 0) or 1? On my machine ,the result of your code is 1. I think that's nothing to do with macros. Before expanding the macro (|| (get a 0) (b)), (get a 0) and (b) will be evaluated and the macro just get arguments 1 and nil. If you want result of (get a 0), you should use (|| '(get a 0) (b))

How to have multiple if statements inside a function in Clojure?

I want to do this in Clojure:
int i=1;j=2;k=3;
str r;
cin>>r;
if(r=="A")
cout<<i; (i.e., print 1)
if(r=="J")
cout<<j; (i.e., print 2)
if(r=="K")
cout<<k; (i.e., print 3)
else
do something else
I am doing it like this in clojure:
(defn str-to-num [c]
(if ( = (str (first c )) "A")
1
(java.lang.Integer/valueOf (str (first c))))
(if ( = (str (first c )) "J")
2
(java.lang.Integer/valueOf (str (first c))))
(if ( = (str (first c )) "K")
3
(java.lang.Integer/valueOf (str (first c))))
)
But, I'm getting an error. Could someone tell what I'm doing wrong?
All of the if blocks are run, one after the other, regardless of what any of them return. If you want if / else / chaining you should use cond or case (though the two branches of a standard if work fine if there are only two options).
Your first two if blocks can't do anything meaningful except throw an error. And that is exactly what will happen for most inputs.
"A", "J", and "K" are not valid numbers, so trying to parse them will throw an error.
The only meaningful things this function can do is return the first letter of a string as a number if it is parsible as one.
user> (str-to-num "A")
NumberFormatException For input string: "A" java.lang.NumberFormatException.forInputString (NumberFormatException.java:65)
user> (str-to-num "J")
NumberFormatException For input string: "J" java.lang.NumberFormatException.forInputString (NumberFormatException.java:65)
user> (str-to-num "K")
NumberFormatException For input string: "K" java.lang.NumberFormatException.forInputString (NumberFormatException.java:65)
user> (str-to-num "100")
1
perhaps you wanted something like:
user> (defn str-to-num [c]
(case (first c)
\A 1
\J 2
\K 3
(int (first c))))
#'user/str-to-num
user> (str-to-num "A")
1
user> (str-to-num "J")
2
user> (str-to-num "K")
3
user> (str-to-num "L")
76
user> (str-to-num "☃")
9731
Alternately:
user> (defn str-to-num [c]
(case (first c)
\A 1
\J 2
\K 3
(Integer/parseInt (subs c 0 1))))
#'user/str-to-num
user> (str-to-num "9")
9
The problem is with the form of your if statement
You have
(if ( = (str (first c )) "A")
1
(java.lang.Integer/valueOf (str (first c))))
The form of if is
(if (cond)
trueResult
falseResult)
So your "working version" will return 1 if you input A. If you input any other string, it actually throws an error. But, if an error were not thrown, all three if statements would be executed, and the result of the last one is actually returned.
This is closer to your C++ code:
(defn str-to-num [c]
(if ( = (str (first c )) "A") (print 1))
(if ( = (str (first c )) "J") (print 2))
(if ( = (str (first c )) "K") (print 3)))

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]))