"SQL, Lisp, and Haskell are the only programming languages that I've seen where one spends more time thinking than typing."
- Philip Greenspun
Odpowiedź na końcu wpisu.
W tym cyklu nie będzie poznawania podstawowych funkcji, a raczej ich zastosowanie w akcji. Przewiną się wszystkie poznane już w poprzedniej części konstrukcje oraz pojawią się bardziej zaawansowane funkcje. Będzie więcej kombinowania. Dodatkowo pojawią się przeszkody w postaci zakazów użycia niektórych funkcji.
Zalecam użycie Eclipse (dowolna edycja, może być C++, bo mało zajmuje) oraz wtyczkę Counterclockwise (do Clojure), którą można zainstalować z poziomu Eclipse poprzez Help->Eclipse Marketplace... Po utworzeniu projektu Clojure należy utworzyć namespace np. core. Potem uruchomić przyciskiem Run. Uruchomi się w ten sposób linia poleceń Clojure, gdzie można testować kod. Jeżeli program wpadnie w nieskończoną pętlę, bądź się przywiesi, to można go zatrzymać przy pomocy ikonki z trybikiem lub Ctrl+I.
Problem 1: Last Element
T1: (= (__ [1 2 3 4 5]) 5) T2: (= (__ '(5 4 3)) 3) T3: (= (__ ["b" "c" "d"]) "d")
E1: #(first (reverse %))
|
Problem 2: Penultimate Element
T1: (= (__ (list 1 2 3 4 5)) 4) T2: (= (__ ["a" "b" "c"]) "b") T3: (= (__ [[1 2] [3 4]]) [1 2])
E1: #(second (reverse %)) E2: #(last (butlast %))
|
Problem 3: Nth element
Funkcja take bierze n elementów z listy. Jednak autor testu przyjął podstawę 0. Stąd funkcja musi wziąć o jeden element więcej. Szukany element będzie na ostatniej pozycji z obciętej listy.
T1: (= (__ '(4 5 6 7) 2) 6) T2: (= (__ [:a :b :c] 0) :a) T3: (= (__ [1 2 3 4] 1) 2) T4: (= (__ '([1 2] [3 4] [5 6]) 2) [5 6])
E1: #(last (take (inc %2) %1))
|
Problem 4: Count a Sequence
Pierwszy sprytny sposób to nudne zliczanie każdego elementu w pętli : E1.
Drugi sprytny sposób: E2, to utworzenie listy jedynek za pomocą funkcji map, które potem będą zsumowane.
T1: (= (__ '(1 2 3 3 1)) 5) T2: (= (__ "Hello World") 11) T3: (= (__ [[1 2] [3 4] [5 6]]) 3) T4: (= (__ '(13)) 1) T5: (= (__ '(:a :b :c)) 3)
E1: #(loop [c 0 l %] (if (empty? l) c (recur (inc c) (rest l)))) E2: #(reduce + (map (fn [e] 1) %))
|
Problem 5: Sum it all up
Dużo pracy tu nie ma, bo wykorzystam poprzednią funkcję, która zamiast zliczać jedynki będzie sumować poszczególne elementy.
T1: (= (__ [1 2 3]) 6) T2: (= (__ (list 0 -2 5 5)) 8) T3: (= (__ #{4 2 1}) 7) T4: (= (__ '(0 0 -1)) -1) T5: (= (__ '(1 10 3)) 14)
E1: #(loop [sum 0 l %] (if (empty? l) sum (recur (+ sum (first l)) (rest l)))) E2: #(apply + %) E3: #(reduce + %)
|
Problem 6: Find the odd numbers
Zadanie polega na znalezieniu wszystkich elementów nieparzystych z podanej listy i zwrócenie ich jako listy. Znając już makro for zadanie będzie dość proste (E1). Zmodyfikuję też poprzednią pętlę i podam jako E2.
T1: (= (__ #{1 2 3 4 5}) '(1 3 5)) T2: (= (__ [4 2 1 6]) '(1)) T3: (= (__ [2 2 4 6]) '()) T4: (= (__ [1 1 1 3]) '(1 1 1 3))
E1: #(for [x % :when (odd? x)] x) E2: #(loop [wyn [] lst %] (if (empty? lst) wyn (recur (if (odd? (first lst)) (conj wyn (first lst)) wyn) (rest lst))))
|
Problem 7: Reverse a Sequence
T1: (= (__ [1 2 3 4 5]) [5 4 3 2 1]) T2: (= (__ (sorted-set 5 7 2 7)) '(7 5 2)) T3: (= (__ [[1 2][3 4][5 6]]) [[5 6][3 4][1 2]])
E1: #(loop [wyn [] lst %] (if (empty? lst) wyn (recur (conj wyn (last lst)) (butlast lst))))
|
Problem 8: Palindrome detector.
Ciąg jest palidromem, jeżeli pierwsza połowa sekwencji jego elementów jest równa odwróconej drugiej połowie. Jeżeli liczba elementów ciągu jest nieparzysta środkowy znak się ignoruje. Należy więc wziąć liczbę n elementów ciągu , podzielić całkowicie przez dwa (funkcja quot), wziąć n/2 pierwszych elementów , odwrócić listę, wziąć n/2 pierwszych elementów i porównać listy (E1). Drugi sposób to porównywać pierwszy element z ostatnim (przy okazji usuwać te elementy), aż lista nie będzie pusta (E2). Trzeci sposób to wziąć sobie jakiś licznik i porównywać n-ty z k-n element listy, gdzie k to długość listy, a n: <0, k-1>.
T1: (false? (__ '(1 2 3 4 5))) T2: (true? (__ "racecar")) T3: (true? (__ [:foo :bar :foo])) T4: (true? (__ '(1 1 3 3 1 1))) T5: (false? (__ '(:a :b :c)))
E1: #( let [lst % n (quot (count lst) 2) pp (take n lst) dp (take n (reverse lst))] (if (< n 1) true (reduce (fn [x y] (and x y)) (map (fn [a b] (= a b)) pp dp))))
E2: #( let [lst % n (quot (count lst) 2)] (loop [f (first lst) l (last lst) tmp lst] (if (empty? tmp) true (if (not= f l) false (recur (second tmp) (last (butlast tmp)) (rest (butlast tmp)))))))
E3: #( let [v (vec %) k (count v) n (quot k 2)] (loop [f 0 l (dec k)] (if (>= f n) true (if (not= (v f) (v l)) false (recur (inc f) (dec l))))))
|
Odpowiedź na zagadkę: Żadnego. Problem obejdzie się w sofcie.
Brak komentarzy:
Prześlij komentarz