"The Grid. A digital frontier. I tried to picture clusters of information as they move through the computer. What did they look like? Ships? Motorcycles? Were the circuits like freeways? I kept dreaming of a world I thought I’d never see. And then, one day, I got in." — Tron: Legacy

2012-11-22

Clojure Easy 1

"SQL, Lisp, and Haskell are the only programming languages that I've seen where one spends more time thinking than typing."
- Philip Greenspun


Na początek zagadka: Ilu inżynierów od sprzętu komputerowego potrzeba by wymienić żarówkę?
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


Zadanie polega na wypisaniu ostatniego elementu kolekcji. Aby zadanie nie było zbyt łatwe nie można użyć funkcji last. Oczywiście nie utrudnia to nam zadania.
T1: (= (__ [1 2 3 4 5]) 5)
T2: (= (__ '(5 4 3)) 3)
T3: (= (__ ["b" "c" "d"]) "d")

E1: #(first (reverse %))

Problem 2: Penultimate Element


Jeszcze trudniejsze zadanie. Tym razem trzeba podać wartość drugiego elementu od końca.

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


Zadanie polega na podaniu n-tego elementu kolekcji przekazanej do funkcji. Jest jednak haczyk. Nie można użyć funkcji nth.

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


Zadanie polega na wypisaniu ilości elementów listy bez użycia funkcji count
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


Zadanie polega na napisaniu funkcji, która zwróci sumę wszystkich elementów.
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


Zadanie polega na zmianie kolejności elementów kolekcji bez używania funkcji reverse i rseq.

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.


Zadanie polega na napisaniu funkcji, która testuje czy podana sekwencja jest palindromem.
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