# Clojure for Pythonistas & Data Scientists
## Why care?
#### Hello World
```python
print("Hello World!")
```
```clojure
(println "Hello World!")
```
#### Numbers
```python
num = 7
print(num)
flt = 7.2
print(flt)
flt = float(7)
print(flt)
```
```clojure
(def num 7)
(println num)
(def flt 7.2)
(println flt)
(def flt (float 7))
(println flt)
```
#### Strings
```python
word = 'hello'
print(word)
word = "hello"
```
```clojure
(def word "hello")
(println word)
```
#### Math
```python
1 + 2 * 3 / 4
```
```clojure
(+ 1 (/ (* 2 3) 4))
```
```python
11 % 3
```
```clojure
(mod 11 3)
```
```python
7 ** 2
```
```clojure
(Math/pow 7 2)
; or
(defn ** [x n] (reduce * (repeat n x)))
(** 7 2)
```
```python
"hello" + " " + "world"
```
```clojure
(str "hello" " " "world")
```
#### Data structures
```python
[1, 2, 3]
mylist = []
mylist.append(1)
mylist.append(2)
mylist.append(3)
print(mylist)
```
```clojure
[1 2 3]
(def mylist [])
(conj mylist 1)
(conj mylist 2)
(conj mylist 3)
(println mylist)
```
```python
mylist = [1, 2, 3]
# get first element
mylist[0]
# get last element
mylist[-1]
# get a range
mylist[:1]
# count
len(mylist)
```
```clojure
(def mylist [1 2 3])
# get first element
(first mylist)
(get mylist 0)
(mylist 0)
(nth mylist 0)
# get last element
(last mylist)
(peek mylist)
# get a range
(take 2 mylist)
# count
(count mylist)
```
```python
phonebook = {
"John" : 938477566,
"Jack" : 938377264,
"Jill" : 947662781
}
print(phonebook)
```
```clojure
(def phonebook
{:john 938477566
:jack 938377264
:jill 947662781})
(println phonebook)
```
```python
phonebook["John"]
phonebook["Alex"] = 999555789
print(phonebook)
phonebook["John"] = phonebook["John"] + 1
phonebook.pop("John")
print(phonebook)
```
```clojure
(phonebook :john)
(:john phonebook)
(get phonebook :john)
(assoc phonebook "Alex" 999555789)
(println phonebook)
(def phonebook (assoc phonebook "Alex" 999555789))
(get phonebook "Alex")
(phonebook "Alex")
(update phonebook :john inc)
(dissoc phonebook :john)
```
#### String operations
```python
len("Hello")
```
```clojure
(count "hello")
(.length "hello")
```
```python
"string".index("n")
```
```clojure
(.indexOf "string" "n")
(clojure.string/index-of "string" "n")
```
```python
"hello".count("l")
```
```clojure
(frequencies "hello")
(get (frequencies "hello") \l)
```
```python
"Hello world!"[3:7]
```
```clojure
(subs "Hello world!" 3 7)
```
```python
"abc".upper()
"ABC".lower()
```
```clojure
(clojure.string/upper-case "abc")
(.toUpperCase "abc")
(clojure.string/lower-case "ABC")
(.toLowerCase "ABC")
```
```python
"hey there".split(" ")
```
```clojure
(clojure.string/split "hey there" #" ")
```
#### Conditions
```python
x = 2
x == 2 # True
x == 3 # False
x < 3 # True
```
```clojure
(def x 2)
(= x 2) ; true
(= x 3) ; false
(< x 3) ; true
```
```python
name = "John"
age = 23
if name == "John" and age == 23:
print("Your name is John, and you are also 23 years old.")
if name == "John" or name == "Rick":
print("Your name is either John or Rick.")
```
```clojure
(def nme "John")
(def age 23)
(if (and (= nme "John") (= age 23))
(println "Your name is John, and you are also 23 years old."))
(if (or (= nme "John") (= nme "Rick")
(println "Your name is John, and you are also 23 years old."))
(when (and (= nme "John") (= age 23))
(println "Your name is John, and you are also 23 years old."))
(case nme
"John" :john
"Rick" :rick
:who?)
(cond
(< age 18) "You can't drink for sure"
(<= 18 age 21) "Somewhere you can drink, somewhere you can't"
"Have fun drinking (not too much)!")
```
```python
name = "John"
if name in ["John", "Rick"]:
print("Your name is either John or Rick.")
```
```clojure
(def nme "John")
(when (some #{"John" "Rick"} nme)
(println "Your name is either John or Rick."))
```
```python
x = [1,2,3]
y = [1,2,3]
print(x == y) # True
print(x is y) # False
```
```clojure
(def x [1 2 3])
(def y [1 2 3])
(= x y) ; true
(identical? x y) ; false
```
```python
not False # True
```
```clojure
(not false)
(if-not true 1 0)
(when-not true (println "This won't print"))
```
#### Loops & co.
```python
primes = [2, 3, 5, 7]
for prime in primes:
print(prime + 1)
[p + 1 for p in primes]
numbers = list(range(100))
[n for n in numbers if n % 2 == 0]
list(filter(lambda x: (x % 2 == 0), numbers))
```
```clojure
(def primes [2 3 5 7])
(for [p primes] (inc p))
(map inc primes)
(loop [f (first primes) r (rest primes) res []]
(if f
(recur (first r) (rest r) (conj res (inc f)))
res))
(filter even? (range 100))
```
#### Functions
```python
def my_function():
print("Hello there!")
```
```clojure
(defn my-function
(println "Hello there!"))
```
```python
def my_function_with_args(username, greeting):
print("Hello, %s, I wish you %s" % (username, greeting))
```
```clojure
(defn my-function-with-args
[username greeting]
(println "Hello," username ", I wish you" greeting))
```
```python
def sum_two_numbers(a, b):
return a + b
```
```clojure
(defn sum-2-numbers
[a b]
(+ a b))
```
#### Laziness
```python
range(10)
list(range(10))
```
```clojure
(range 10)
(->> (range) (take 10) (map inc) (filter even?))
```
```python
import random
def lottery():
# returns 6 numbers between 1 and 40
for i in range(6):
yield random.randint(1, 40)
# returns a 7th number between 1 and 15
yield random.randint(1,15)
for random_number in lottery():
print("And the next number is... %d!" %(random_number))
```
```clojure
(defn lottery
[]
(let [a (for [i (range 6)] (inc (rand-int 40)))
b (inc (rand-int 15))]
(concat a [b])))
(defn random-generator
[n]
(inc (rand-int n)))
(defn random-numbers
[n]
(repeatedly #(random-generator n)))
(defn lottery
[]
(let [a (take 6 (random-numbers 40))
b (take 1 (random-numbers 15))]
(flatten [a b])))
(doseq [l (lottery)]
(println "And the next number is..." l))
(def lottery
(let [n (atom 0)]
(repeatedly
(fn []
(swap! n inc)
(if (zero? (mod @n 6))
(inc (rand-int 15))
(inc (rand-int 40)))))))
(doseq [l (take 6 lottery)]
(println "And the next number is..." l))
```