2014/1/14

  • 4clojureを解いていった過程を愚直にメモしておきます。
  • あとで見返して復習するためです。
  • 基本的に時間のかかった問題と重要と思われるものだけ記述します。
  • この記事は随時更新してきます。

1 A nil key【難しい】

- #134
- Difficulty: Elementary
- Topics: maps

Write a function which, given a key and map, returns true iff the map
contains an entry with that key and its value is nil.

(true?  (__ :a {:a nil :b 2}))
(false? (__ :b {:a nil :b 2}))
(false? (__ :c {:a nil :b 2}))

#(nil? (%2 %1 '()))

経過

一瞬、マップをキーにして、値を取るようにすればいいと考えたけど

user> (:b {:a nil :b 2})
2

外側のカッコの使いかたがわからん。 次に思いついたのがget関数。 でもこれは引数の位置が合わない。

user> (get :b {:a nil :b 2})
nil
user> (get {:a nil :b 2} :b)
2

キーは第2引数にしないとnilが返ってきてしまうのでNG。 そもそも問題分のiffの意味がわからないのでググル。

わかったこと。問題にあるiffとは「if and only if」の略で同値のこと。

0 and 0 => true
0 and 1 => false
1 and 0 => false
1 and 1 => true

true?,false?,nil?関数はiffの関数で完全に同値でないと真を返さない。

user> (true? true)
true
user> (true? 1)
false
user> (true? 2)
false
user> (false? nil)
false
user> (false? false)
true
user> (false? "")
false
user> (nil? nil)
true
user> (nil? false)
false
user> (nil? "")
false
user> (nil? '())
false

いろいろ指向錯誤した結果、即時呼び出しする無名関数を 定義すれば良いと思いついた。

こんなやつ。

(#(str %1 %2) "Hello" "World!")

似た記述をjavascriptで良くみますな。

この後いろいろ試す。

:

結構試行錯誤したうえでやっとできた。

user>  (#(nil? (%2 %1 '())) :a {:a nil :b 2})
true
user>  (#(nil? (%2 %1 '())) :b {:a nil :b 2})
false
user>  (#(nil? (%2 %1 '())) :c {:a nil :b 2})
false

2 For the win 【forの使いかた】

#145
Difficulty:	Elementary
Topics:	core-functions seqs

Clojure's for macro is a tremendously versatile mechanism 
for producing a sequence based on some other sequence(s).
It can take some time to understand how to use it properly,
but that investment will be paid back with clear,
 concise sequence-wrangling later. With that in mind,
 read over these for expressions and try to see 
how each of them produces the same result.
(= __ (for [x (range 40)
	    :when (= 1 (rem x 4))]
	x))

(= __ (for [x (iterate #(+ 4 %) 0)
	    :let [z (inc x)]
	    :while (< z 40)]
	z))

(= __ (for [[x y] (partition 2 (range 20))]
	(+ x y)))

(map inc (filter #(= 0 (rem % 4)) (range 40)))

経過

forを読めば、どんなシーケンスを返すかは想像できるが 単純にそのシーケンスを書くのは意味がない。

この問題は、下記の数列を考える問題。

0から開始して4の倍数に1足した数列を40未満まで出力する。
'(1 5 9 13 17 21 25 29 33 37)

でも実際forを読むことはできても、これと同じ挙動を捻りだすのは難題。

以下のような感じで作れた。

user> (range 40)
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39)
user> (filter #(rem % 4) (range 40))
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39)
user> (filter #((= 0 (rem % 4))) (range 40))
ClassCastException java.lang.Boolean cannot be cast to clojure.lang.IFn  user/eval6704/fn--6705 (NO_SOURCE_FILE:1)
user> (filter #((not (rem % 4))) (range 40))
ClassCastException java.lang.Boolean cannot be cast to clojure.lang.IFn  user/eval6851/fn--6852 (NO_SOURCE_FILE:1)
user> (rem 4 4)
0
user> (filter #(= 0 (rem % 4)) (range 40))
(0 4 8 12 16 20 24 28 32 36)
user> (map inc (filter #(= 0 (rem % 4)) (range 40)))
(1 5 9 13 17 21 25 29 33 37)

3 Logical falsity and truth【真偽について】

#152
Difficulty:	Elementary
Topics:	logic

In Clojure, only nil and false represent the values 
 of logical falsity in conditional tests -
  anything else is logical truth.
(= __ (if-not false 1 0))
(= __ (if-not nil 1 0))
(= __ (if true 1 0))
(= __ (if [] 1 0))
(= __ (if [0] 1 0))
(= __ (if 0 1 0))
(= __ (if 1 1 0))

1

要点 clojureでは、falseとnilだけが偽。それ以外は全て真。

4 Subset and Superset【重量】

#162
Difficulty:	Elementary
Topics:	set-theory

Set A is a subset of set B, or equivalently B is a superset of A,
 if A is "contained" inside B. A and B may coincide.
(clojure.set/superset? __ #{2})
(clojure.set/subset? #{1} __)
(clojure.set/superset? __ #{1 2})
(clojure.set/subset? #{1 2} __)

#{1 2}

経過

user> (clojure.set/subset? #{1} #{1 2})
true
user> (clojure.set/superset? #{1 2} #{1 2})
true
user> (clojure.set/superset? #{1 2} #{1 2})
true
user> (clojure.set/subset? #{1 2} #{1 2})
true

内容が同じ場合は、superset?もsubset?も真になる。

要点

Bの集合があり、その中にAの集合が含まれるとき、 BがAのsupersetとなり、AはBのsubsetとなる。

+---------+
| +-+     |
| |A| B   |
| +-+     |
+---------

5 Map Defaults

Difficulty:	Elementary
Topics:	seqs
#156

When retrieving values from a map,
 you can specify default values in case the key is not found:

(= 2 (:foo {:bar 0, :baz 1} 2))

However, what if you want the map itself to contain
 the default values? Write a function which takes a default value
 and a sequence of keys and constructs a map.
(= (__ 0 [:a :b :c]) {:a 0 :b 0 :c 0})
(= (__ "x" [1 2 3]) {1 "x" 2 "x" 3 "x"})
(= (__ [:a :b] [:foo :bar]) {:foo [:a :b] :bar [:a :b]})


経過

キーからなる配列とひとつの値を指定してmapをつくる関数を考える問題。

6 Lists: conj【重要】

#5
Difficulty:	Elementary
Topics:	

When operating on a list, the conj function will return
 a new list with one or more items "added" to the front.
test not run	

(= __ (conj '(2 3 4) 1))
test not run	

(= __ (conj '(3 4) 2 1))

'(1 2 3 4)

conjは第2以降の引数を順番にlistの先頭にくっつけていく。 複数の引数をフラットなリストにする感じ。

user> (conj '(2 3 4) 1)
(1 2 3 4)
user> (conj '(3 4) 1 2)
(2 1 3 4)

↑引数を左から順番に、先頭に追加していくことに注意。

一方、consは追加する要素は、第1引数にひとつだけとる。 こちらも同様に先頭へ追加していく。

user> (cons 1 '(2 3))
(1 2 3)
user> (cons 1 2 '(2 3))
; Evaluation aborted.

7 Intro to Vectors【重要】

#6
Intro to VectorsSolutions
Difficulty:	Elementary
Topics:	
Vectors can be constructed several ways. You can compare them with lists.
test not run
(= [__]
  (list :a :b :c)
  (vec '(:a :b :c))
  (vector :a :b :c))

:a :b :c

リストをベクタに変換する

user> (vec '(:a :b :c))
[:a :b :c]

ベクタを作る

user> (vector :a :b :c)
[:a :b :c]

それぞれの返り値がベクタなので最初わからなかったが REPLに入れたらtrueが帰ってきた!

user>  (= [:a :b :c] (list :a :b :c) (vec '(:a :b :c)) (vector :a :b :c))
true

= 関数は中身だけ見るのね。

で、これを4clojureに回答しても、正解にならない。。。

(= [:a :b :c] (list :a :b :c) (vec '(:a :b :c)) (vector :a :b :c))

REPLではtrueになるのになぜ? (= (lis '(:a :b :c)) (list :a :b :c) (vec '(:a :b :c)) (vector :a :b :c))

-> 問題をよくみたらカギカッコが含まれていた。

「[___]」つまり「[:a :b :c]」のうち中身の「:a :b :c」だけを書けばよかっ た。だから下記であってたということ。

user>  (= [:a :b :c] (list :a :b :c) (vec '(:a :b :c)) (vector :a :b :c))

この問題でわかることは、ベクタには「'」がいらないということ。

'[a b c]
ではなくて
[a b c]
でよいとうこと。

8 Vectors :conj【重要】

注意!ベクタの場合は、リストと違って後ろに追加されていく。

user> (= [1 2 3 4] (conj [1 2 3] 4))
true
user> (= [1 2 3 4] (conj [1 2] 3 4))
true

9 Intro to Sets【重要】

(= __ (set '(:a :a :b :c :c :c :c :d :d)))
(= __ (clojure.set/union #{:a :b :c} #{:b :c :d}))

とりあえずリテラルを書いてみる。

user> (= #{:a :a :b :c :c :c :c :d :d} (set '(:a :a :b :c :c :c :c :d :d)))
; Evaluation aborted.

...うまくいかない。なぜアボートになるのか。。。そうかsetは値はユニーク になるものだった。set関数の引数が非ユニークだからそのままリテラル書いた けどリテラルは当然setの仕様どおりに記述しなくちゃならないからユニークに しなくちゃだね。

user> (= #{:a :b :c :d} (set '(:a :a :b :c :c :c :c :d :d)))
true

union関数はふたつのsetを合成するものかな。

user> (clojure.set/union #{:a :b :c} #{:b :c :d})
#{:a :c :b :d}

10 Sets: conj【重要】

(= #{1 2 3 4} (conj #{1 4 3} __))

試す。

user> (conj #{1 4 3} #{2 3 5})
#{1 3 4 #{2 3 5}}
user> (conj #{1 4 3} 2 3 5)
#{1 2 3 4 5}

なるほど。理解した。setは中身がソートされるのね。

user> (= #{1 2 3 4} (conj #{1 4 3} 2 3))
true

11 Intro to Maps

(= __ ((hash-map :a 10, :b 20, :c 30) :b))
(= __ (:b {:a 10, :b 20, :c 30}))
user> (= 20 ((hash-map :a 10, :b 20, :c 30) :b))
true
user> (= 20 (:b {:a 10, :b 20, :c 30}))
true

12 Maps: conj

(= {:a 1, :b 2, :c 3} (conj {:a 1} __ [:c 3]))

Mapにconjするにはキーと値のペアのベクタを渡す。

user> (conj {:a 1} [:b 2] [:c 3])
{:c 3, :b 2, :a 1}

13 Intro to Sequences

(= __ (first '(3 2 1)))
(= __ (second [2 3 4]))
(= __ (last (list 1 2 3)))

14 Sequences: rest

(= __ (rest [10 20 30 40]))
(= '(20 30 40) (rest [10 20 30 40]))

15 Intro to Functions【重要】

(= __ ((fn add-five [x] (+ x 5)) 3))
(= __ ((fn [x] (+ x 5)) 3))
(= __ (#(+ % 5) 3))
(= __ ((partial + 5) 3))

無名関数をカッコでくるむことで即時呼び出しされる。 partial関数ってなに?初見だ。

16 Double Down

Write a function which doubles a number.
(= (__ 2) 4)
(= (__ 3) 6)
(= (__ 11) 22)
(= (__ 7) 14)

答え

(= (#(* 2 %) 2) 4)

17 Hello World

Write a function which returns a personalized greeting.
(= (__ "Dave") "Hello, Dave!")
(= (__ "Jenn") "Hello, Jenn!")
(= (__ "Rhea") "Hello, Rhea!")

user> (= (format "Hello, %s!" "Rhea") "Hello, Rhea!")
true

18 Sequences: map【重要】

The map function takes two arguments: a function (f) and a sequence (s).
Map returns a new sequence consisting of the result of applying f to each item of s.
Do not confuse the map function with the map data structure.
(= __ (map #(+ % 5) '(1 2 3)))

19 Sequences: filter【重要】

The filter function takes two arguments:
a predicate function (f) and a sequence (s).
Filter returns a new sequence consisting 
of all the items of s for which (f item) returns true.

(= __ (filter #(> % 5) '(3 4 5 6 7)))

20 #35 Local bindings

Difficulty:     Elementary
Topics: syntax


Clojure lets you give local names to values using the special let-form.
test not run    
(= __ (let [x 5] (+ 2 x)))
test not run    
(= __ (let [x 3, y 10] (- y x)))
test not run    
(= __ (let [x 21] (let [y 3] (/ x y))))

21 #37 Regular Expressions

Difficulty:     Elementary
Topics: regex syntax

Regex patterns are supported with a special reader macro.
test not run    
(= __ (apply str (re-seq #"[A-Z]+" "bA1B3Ce ")))
user> (= "ABC" (apply str (re-seq #"[A-Z]+" "bA1B3Ce ")))
true

22 #64 Intro to Reduce

Difficulty:     Elementary
Topics: seqs

Reduce takes a 2 argument function and an optional starting value.
It then applies the function to the first 2 items in the sequence
(or the starting value and the first element of the sequence).
In the next iteration the function will be called
 on the previous return value and the next item from the sequence,
 thus reducing the entire collection to one value.
 Don't worry, it's not as complicated as it sounds.
(= 15 (reduce __ [1 2 3 4 5]))
(=  0 (reduce __ []))
(=  6 (reduce __ 1 [2 3]))
user> (= 15 (reduce + [1 2 3 4 5]))
true

23 #57 Simple Recursion【難しい】

Difficulty:     Elementary
Topics: recursion

A recursive function is a function which calls itself.
This is one of the fundamental techniques used in functional programming.
(= __
  ((fn foo [x]
    (when (> x 0)
      (conj (foo (dec x)) x)))
    5))
user> (= '(5 4 3 2 1) ((fn foo [x] (when (> x 0) (conj (foo (dec x)) x))) 5))
true

24 S#71 Rearranging Code: ->【重要】

Difficulty:     Elementary
Topics: 

The -> macro threads an expression x through a variable number of forms. 
First, x is inserted as the second item in the first form,
 making a list of it if it is not a list already.
Then the first form is inserted as the second item in the second form,
making a list of that form if necessary.
This process continues for all the forms.
Using -> can sometimes make your code more readable.

(= (__ (sort (rest (reverse [2 5 4 1 3 6]))))
   (-> [2 5 4 1 3 6] reverse rest sort __)
   5)
(= (last (sort (rest (reverse [2 5 4 1 3 6]))))
   (-> [2 5 4 1 3 6] reverse rest sort last)
   5)

25 #68 Recurring Theme

Difficulty:     Elementary
Topics: recursion

Clojure only has one non-stack-consuming looping construct: recur.
Either a function or a loop can be used as the recursion point. 
Either way, recur rebinds the bindings of the recursion point to the values it is passed.
Recur must be called from the tail-position, and calling it elsewhere will result in an error.

(= __
  (loop [x 5
	 result []]
    (if (> x 0)
      (recur (dec x) (conj result (+ 2 x)))
      result)))

26 S#72 Rearranging Code: ->>【重要】

Difficulty:     Elementary
Topics: 


The ->> macro threads an expression x through a variable number of forms. First, x is inserted as the last item in the first form, making a list of it if it is not a list already. Then the first form is inserted as the last item in the second form, making a list of that form if necessary. This process continues for all the forms. Using ->> can sometimes make your code more readable.
test not run    
(= (__ (map inc (take 3 (drop 2 [2 5 4 1 3 6]))))
   (->> [2 5 4 1 3 6] (drop 2) (take 3) (map inc) (__))
   11)

こたえ

(= (apply + (map inc (take 3 (drop 2 [2 5 4 1 3 6]))))
   (->> [2 5 4 1 3 6] (drop 2) (take 3) (map inc) (apply +))
   11)

27 Last Element【難しい】

Difficulty:     Easy
Topics: seqs core-functions

Write a function which returns the last element in a sequence.
(= (__ [1 2 3 4 5]) 5)
(= (__ '(5 4 3)) 3)
(= (__ ["b" "c" "d"]) "d")

lastは使っちゃダメらしい。

難しい。ここみてカンニング。。。 http://stackoverflow.com/questions/8264881/clojure-find-last-element-without-using-last-function

user> (= (#(first (reverse %)) '(5 4 3)) 3)
true

無名関数を使い、さらに即時呼出するとか。絶対おもいつかん。。。

28 #20 Penultimate Element【難しい】

Difficulty:     Easy
Topics: seqs

Write a function which returns the second to last element from a sequence.

(= (__ (list 1 2 3 4 5)) 4)
(= (__ ["a" "b" "c"]) "b")
(= (__ [[1 2] [3 4]]) [1 2])

先の問題にあった「Last Element」と同じ。

user> (= (#(second (reverse %)) (list 1 2 3 4 5)) 4)
true
user> (= (#(second (reverse %)) ["a" "b" "c"]) "b")
true
user> (= (#(second (reverse %)) [[1 2] [3 4]]) [1 2])
true
blog comments powered by Disqus