How to double loop over a vector of strings in Clojure? - function

I have this function that checks the cities in a csv file if they have over a population of 500000.
I saved all the found cities to a vector but now want to loop over the vector twice in order to find the pairs of cities that are close to each other(less than 500km)(i already have a function that checks if two cities are close)
Here is what I have so far:
(defn closest-city-pairs []
(with-open [rdr (reader)]
(vec
(for [line (drop 1 (line-seq rdr))
:let [y (string/split line #",")]
:when (= true (large(y 0)))]
(let [newVec (conj [] (y 0))]
(for[x newVec
y newVec
:when (= true (close x y))]
(let [newNewVec (conj [] (x y))]
(println newNewVec))))))))
It doesn't seem to want to print but my logic and all the parentheses seem to make sense and in order? Any help would be great

(require '[clojure.math.combinatorics :as comb])
(require '[clojure.data.csv :as csv])
(with-open [r (io/reader "cities.csv")]
(let [cities (->> (csv/read-csv r) (into [] (comp cat (filter large-city?))))]
(filter close-to-each-other? (comb/combinations cities 2))))

Here is an outline of what you can do, written as a unit test:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(def nums [1 2 3 11 12 13])
(defn close?
[x y]
(<= (Math/abs (- x y)) 5))
(dotest
(let [close-pairs (vec
(for [x nums
y nums
:when (and (not= x y)
(close? x y))]
[x y]))]
(spyx close-pairs))
)
with result:
close-pairs => [[1 2] [1 3] [2 1] [2 3] [3 1] [3 2]
[11 12] [11 13] [12 11] [12 13] [13 11] [13 12]]
so we get a lot of duplicates. We can eliminate them by simply sending the output into a set, then removing duplicate sets:
(let [close-pairs (vec
(distinct
(for [x nums
y nums
:when (and (not= x y)
(close? x y))]
#{x y})))]
(spyx close-pairs))
with result:
close-pairs => [#{1 2} #{1 3} #{3 2} #{12 11} #{13 11} #{13 12}]
You can avoid the set trick (and the work duplication) if you get fancier with the for expression, and use indexes for each value. See the docs for the indexed function
(indexed [:a :b :c]) => ([0 :a] [1 :b] [2 :c])
And we can then use the :when clause like so:
(dotest
(let [nums-indexed (indexed nums)
close-pairs (vec
(for [[ix x] nums-indexed
[iy y] nums-indexed
:when (and (< ix iy)
(close? x y) )]
[x y]))]
(spyx close-pairs)))
with result:
close-pairs => [[1 2] [1 3] [2 3] [11 12] [11 13] [12 13]]
One could reduce the duplicate looping even further with judicious use of the :while clause, but that is left as an exercise for the reader.
P.S. You'll need to add [tupelo "0.9.169"] to :dependencies in your project.clj to access the spyx and indexed functions.

Related

Functions to create a simplified darts game with randomized numbers and a win condition

I managed to create a pair of numbers with code
(defn dart-throwing []
[(- (* 2 (rand-int 2)) 1) (- (* 2 (rand-int 2)) 1)])
(def onetrial (dart-throwing))
But I do not know how to create my win condition which would be x^2 + y^2 < 1
I tried writing
(defn won? [x y]
(< (+ (* x x) (* y y)) 1))
(won? onetrial)
I expected it to check the pair [] from dart-throwing and check if it was less than 1 giving a true or false
I would appreciate it if I had some help, thank you
Your won? function expects two arguments, an x and a y. Your onetrial is a vector of two elements, but it is a single argument here.
You have a couple of options:
You can use apply to 'spread' the vector into the argument list.
(apply won? onetrial)
OR
You can rewrite won? slightly using destructuring
(defn won? [[x y]]
(< (+ (* x x) (* y y)) 1))
Your code does the same like:
(defn dart-throwing []
[(rand-nth [-1 1])
(rand-nth [-1 1])
(def onetrial (dart-throwing))
rand-nth chooses deliberately from the given collection - in this case -1 and 1.
And here is the problem: -1 squared is 1 - so (+ (* x x) (* y y)) will never be < than 1.
So: What is the point of the won? function?
Or shouldn't dart-throwing return some float between -1 and 1? a selection from the range? In this case rand-int is wrong. It must be then rand.
so, instead of (- (* 2 (rand-int 2)) 1) it should be then (- (* 2 (rand)) 1). However, rand excludes the upper limit - in this case 1. One could send the upper limit to 1 + Float/MIN_VALUE to include 1. Or one keeps it but randomly choose between -1 and 1 and multiply them with the result - then one would get 1 included ... - but it wouldn't be a even distribution ...
as far as i can see, you've got an incorrect throwing implementation, returning components -1 | 1 instead of -1 | 0 | 1.
what i would propose, is something like this:
(defn rand-axis [] (dec (rand-int 3)))
user> (repeatedly 10 rand-axis)
;;=> (-1 -1 0 -1 0 -1 -1 0 1 -1)
then you just use it in an attempt function:
(defn attempt [] [(rand-axis) (rand-axis)])
and the won? seems to be like the following:
(defn won? [[x y]] (zero? (+ (* x x) (* y y))))
check it:
user> (doseq [att (repeatedly 10 attempt)]
(println (str "throw:\t" att "\twon?:\t" (won? att))))
;; throw: [1 -1] won?: false
;; throw: [-1 1] won?: false
;; throw: [1 -1] won?: false
;; throw: [0 1] won?: false
;; throw: [1 1] won?: false
;; throw: [-1 -1] won?: false
;; throw: [0 1] won?: false
;; throw: [-1 1] won?: false
;; throw: [0 0] won?: true
;; throw: [-1 0] won?: false
moreover, since the only winning situation is [0 0], won? counld be like this:
(defn won? [pair] (= [0 0] pair))
or like this:
(defn won? [[a b]] (= 0 a b))
or even like this:
(def won? (comp boolean #{[0 0]}))

Why does my function dropR (reverse of Prelude drop) look the way it does?

I'm still new to programming and to practice writing functions, I attempted to reverse the effects of the Prelude drop;
drop :: Int -> [a] -> [a]
drop 0 [] = []
drop 0 (x:xs) = x:xs
drop n [] = []
drop n (x:xs) = drop (n-1) xs
into something I very originally named dropR.
dropR :: Int -> [a] -> [a] -- drops from the right of the list
dropR 0 [] = []
dropR 0 (x:xs) = x:xs
dropR n [] = []
dropR n (x:xs) = reverse (drop (n-1) (reverse xs ++ [x]))
Unfortunately, this didn't work, as the input dropR 2 [1,2,3,4,5] returned [1,2,3,4] and not [1,2,3] as I'd hoped. Using drop 2, I would've gotten 3 values in the list and not 4. I changed the function to;
dropR :: Int -> [a] -> [a] -- drops from the right of the list
dropR 0 [] = []
dropR 0 (x:xs) = x:xs
dropR n [] = []
dropR n (x:xs) = reverse (drop n (reverse xs ++ [x]))
which worked in the way I wanted, but I don't understand why the first one doesn't work. I thought that it would've just reversed the list and taken the same amount of values as the regular drop would after which I could just reverse it.
Why does drop need drop (n-1) and my dropR just need drop n? Does it happen because of recursion in drop and not in dropR?
Let's look at an example:
dropR 2 [1, 2, 3, 4]
In your first attempt, the last line matches, and in it:
n = 2
x = 1
xs = [2, 3, 4]
Therefore:
reverse xs = [4, 3, 2]
reverse xs ++ [x] = [4, 3, 2, 1]
drop (n-1) (reverse xs ++ [x]) = drop 1 [4, 3, 2, 1] = [3, 2, 1]
reverse (drop (n-1) (reverse xs ++ [x])) = [1, 2, 3]
Q.E.D.
In your second attempt, on the other hand:
reverse xs = [4, 3, 2]
reverse xs ++ [x] = [4, 3, 2, 1]
drop n (reverse xs ++ [x]) = drop 2 [4, 3, 2, 1] = [2, 1]
reverse (drop (n-1) (reverse xs ++ [x])) = [1, 2]
Q.E.D.
But have a deeper look.
Observe that reverse xs ++ [x] is actually the same as reverse (x:xs): you're reversing the tail and then sticking the head to the end of it. That's the same as reversing the whole list in the first place.
So what you're really doing there is:
reversing the whole list
dropping n from it
reversing it again
So you might as well just do away with all the cases you have there and just do:
dropR n xs = reverse (drop n (reverse xs))
Or a bit shorter:
dropR n = reverse . drop n . reverse
I think this variant is slightly better, because it expresses the idea more clearly: reverse, then drop n, then reverse again.
#FyodorSoikin explained why n-1 is necessary (because you match with (x:xs), and thus xs is the tail of the list, not the entire list).
However using reverse and ++ [x] are not a good idea. reverse requires the list to have a finite number of items, and ++ [x] will turn the algorithm in an O(n2) one. A better idea to drop the n last items might be to run on the list with two iterators: the first one starts n step more to the right than the second one. In that case if the first iterator reaches the end of the list, we know that the second enumerator should stop.
We thus can implement this with:
dropR :: Int -> [a] -> [a]
dropR n xs = go (drop n xs) xs
where go [] _ = []
go (x:xs) ~(y:ys) = y : go xs ys
this implementation works lazily, and can process infinite lists (in which case it will never drop anything).

Want to be able to save cities that are large into a vector in Clojure

So i want to take cities from a csv file that passes through my large function(which determines if they have a population of over 500000) and if true the city gets saved into a vector. But when I try to save it with my function all the letters are double spaced from each other?
Here is what I have so far:
(defn closest-city-pairs []
(with-open [rdr (reader)]
(vec
(for [line (drop 1 (line-seq rdr))
:let [y (string/split line #",")]
:when (= true (large(y 0)))]
(let [newVec (into [] (y 0))]
(print newVec))))))
Here's the output I'm getting:
[T o r o n t o][M o n t r Θ a l][V a n c o u v e r]...
How do I go about making it single space so it outputs are [Toronto][Montreal]...?
There's a subtle detail: Strings are collections in Clojure (collections of the individual characters), which, mixed with into can cause these issues.
into takes 2 collections and "pours" the second into the first:
user=> (into [1 2 3] (range 4 7))
[1 2 3 4 5 6]
user=> (into [1 2 3] "Hello")
[1 2 3 \H \e \l \l \o]
In the second example, all 5 characters of the string Hello are "added" as 5 new elements of the vector.
In your case, what you probably want is conj:
user=> (conj [1 2 3] "Hello")
[1 2 3 "Hello"]
...now, since you are creating a new vector with just one element, you can use the vector's syntax directly, with something like (let [newVec [(y 0)]] ...), which means that newVec will be a 1-element vector containing the value returned by (y 0), which is the city name in your case.
PS: I see some weird characters in your city names in your example (Q u Θ b e c instead of Q u é b e c), so you might need to check the encoding of your CSV file (eg. save it as UTF-8 for better results).

Clojure recur with multi-arity

I'm probably getting ahead of myself, I'm barely into functions on my first day of learning Clojure, but I thought I would be ambitious and make a recursive function to convert floating values to ternary. If I call the function by name instead of using recur it works great. I understand the problem is that I am just recuring the 1-arity version of the function, is there a standard way to handle recursion in multi-arity functions? The book I'm reading doesn't seem to cover it.
(defn float-to-ternary
([x k s]
(def a (int x))
(def r (- x a))
(def carry-string (str s (. Integer toString a 3)))
(cond
(== r 0) carry-string
(> k 20) carry-string
:default (recur (* 3 r) (inc k) carry-string)
)
)
([x]
(def a (int x))
(def r (- x a))
(def carry-string (str (. Integer toString a 3) "."))
(cond
(== r 0) (str (. Integer toString a 3))
:default (recur (* 3 r) 1 carry-string)
)
)
)
If you want to "recur into a different arity", just explicitly call the function instead of using recur:
(defn float-to-ternary
([x k s]
(def a (int x))
(def r (- x a))
(def carry-string (str s (. Integer toString a 3)))
(cond
(== r 0) carry-string
(> k 20) carry-string
:default (recur (* 3 r) (inc k) carry-string)))
([x]
(def a (int x))
(def r (- x a))
(def carry-string (str (. Integer toString a 3) "."))
(cond
(== r 0) (str (. Integer toString a 3))
:default (float-to-ternary (* 3 r) 1 carry-string))))
This is safe. You "spend" one stack frame when you don't use recur, but the rest of the recursions use recur, so it's fine.
I have some obligatory suggestions too though:
Don't use def inside of functions unless you really have a good reason. def creates global variables that don't go out of scope when the function returns!
Your uses of cond are unnecessary.
In the first body, you want to return carry-string for the first two conditions. You could just make that one condition, connecting the two with an or, which lets you simply use if.
Since the second use only has two outcomes, if again makes more sense.
Taking this into consideration, your code would look more like:
(defn float-to-ternary
([x k s]
(let [a (int x)
r (- x a)
carry-string (str s (. Integer toString a 3))]
(if (or (> k 20) (== r 0))
carry-string
(recur (* 3 r) (inc k) carry-string))))
([x]
(let [a (int x)
r (- x a)
carry-string (str (. Integer toString a 3) ".")]
(if (== r 0)
(str (. Integer toString a 3))
(float-to-ternary (* 3 r) 1 carry-string)))))

Recursive functions in clojure

How does this recursive function work step by step:
(fn foo [n]
(if (< n 10)
[n]
(conj (foo (quot n 10))
(mod n 10))))
I have problem with understanding: lets say i give it as n the number 123, and it will return a vector of its digits. At the last step when arrived to 1 and (< 1 10) it should go to the then-part [n], return [1] and come out of the recursion. So this doesn't happen, what am i missing in the play?
At the last step when arrived to 1 and (< 1 10) it does go to the then-part [n], return [1], but it does NOT come out of the recursion, only out of the innermost invocation.
The evaluation goes as follows:
(foo 123)
(conj (foo 12) 3)
(conj (conj (foo 1) 2) 3)
(conj (conj [1] 2) 3)
(conj [1 2] 3)
[1 2 3]