ボルダリングをやってきた(4)

今週から、いつも行ってるボルダリングジムの、80度と90度の壁のホールドがレイアウト変更になった。何度か書いた、いつもできなかった水色の4番の課題は結局できないまま、なくなってしまった。無念。

で、変わってしまったものは仕方がないので、改めて最初からやることにした。結局今日はピンク(いちばん簡単)の1~8、緑の1~8、水色の1~3と、手足限定のオレンジA、Bに成功。ま、2時間半でこれだけできれば上出来だろう。

コマンドライン引数のワイルドカードを展開する

今日も Python ネタ。

とかいいつつ Ruby の話から入るけど、Ruby はコマンドラインのワイルドカードを展開してくれる。

^o^ > type argv.rb
ARGV.each {|a| puts a}

^o^ > ruby argv.rb *.py
argv.py
binary_search.py
bubble_sort.py
counting_sort.py
count_char.py
count_files.py
csv_read.py
csv_write.py
default_arg.py
dict.py
dictionary.py
dict_keys.py
difference.py
difference2.py
enumerate.py
exception1.py
exception2.py
exception3.py
expand_num.py
(以下略)

でも、Python はそんな気の利いたことしてくれない。

^o^ > type argv.py
import sys

print sys.argv


^o^ > python argv.py *.py
['argv.py', '*.py']

そこで、glob モジュールの出番になる。

 cf. 10.7. glob — Unix 形式のパス名のパターン展開

import sys
import glob

files = glob.glob(sys.argv[1])
for file in files:
    print file

実行:

^o^ > python argv2.py *.py
argv.py
argv2.py
binary_search.py
bubble_sort.py
counting_sort.py
count_char.py
count_files.py
csv_read.py
csv_write.py
default_arg.py
dict.py
dictionary.py
dict_keys.py
difference.py
difference2.py
enumerate.py
exception1.py
exception2.py
exception3.py
expand_num.py
(以下略)

辞書を値でソートする

Python で辞書をソートしようとすると、

>>> h = {'a' : 200, 'b' : 300, 'c' : 500, 'd' : 100, 'e' : 400}
>>> for k, v in sorted(h):
...    print k, v
...
Traceback (most recent call last):
  File "", line 1, in 
ValueError: need more than 1 value to unpack

エラーになった。これは、sorted(h) がキーしか返さないからだ。

>>> for k in sorted(h):
...     print k
...
a
b
c
d
e

キーと値がほしいときにはこうする。

>>> for k, v in sorted(h.items()):
...     print k, v
...
a 200
b 300
c 500
d 100
e 400

辞書の items メソッドは、キーと値からなるタプルのリストを返してくれる。

>>> h.items()
[('a', 200), ('c', 500), ('b', 300), ('e', 400), ('d', 100)]

で、そのタプルの第1要素でソートされる。つまり辞書のキーでソートされるわけだ。

でも、今日やりたいのは値でソートすること。そのためには、sorted に key 引数を渡してやればいい。具体的にはこうする。

>>> for k, v in sorted(h.items(), key=lambda x: x[1]):
...     print k, v
...
d 100
a 200
b 300
e 400
c 500

key 引数に渡しているのは、タプルの第2要素を返す関数だ。つまりこの関数の返り値でソートされるわけだな。
ちなみに、降順にするには、reverse=True を渡してやる。

>>> for k, v in sorted(h.items(), key=lambda x: x[1], reverse=True):
...     print k, v
...
c 500
e 400
b 300
a 200
d 100

__main__.py

今日は Python。

ディレクトリやzipファイルに、__main__.py という名前のスクリプトを含めておくと、そのディレクトリやzipファイルを Python の引数に指定することで、__main__.py が実行される。

例を示そう。

print "Hello, Python."

これを、hello フォルダの中においておく。で、次のように実行すると:

^o^ > ls hello
__main__.py

^o^ > python hello
Hello, Python.

このとおり、__main__.py が実行された。

zipファイルにした場合も同じように動く。

^o^ > cd hello

^o^ > zip hello.zip __main__.py
  adding: __main__.py (164 bytes security) (stored 0%)

^o^ > python hello.zip
Hello, Python.

こんな機能があったとは。でも、どういうときに使うんだろ。

トリボナッチ数をSchemeで

昨日は Python でやったので、今日は Scheme で。

(define tribonacci
  (lambda (n)
    (let loop ((m n) (l '(0 0 1)))
      (if (= m 0)
          '()
          (cons (car l) (loop (- m 1) (append (cdr l) (list (apply + l)))))))))

(print (tribonacci 20))

今回は名前つきletで再帰。
実行:

^o^ > gosh tribonacci.scm
(0 0 1 1 2 4 7 13 24 44 81 149 274 504 927 1705 3136 5768 10609 19513)

トリボナッチ数

トリボナッチ数というのを知った。

 cf. フィボナッチ数,トリボナッチ数 – arik_egaのノート

要するに、フィボナッチ数が前2項の和であるのにたいして、トリボナッチ数は前3項の和である数。最初の3項は 0,0,1。詳しくは Wikipedia で。

Python のジェネレータで書いてみた。

def tribonacci(n):
    a, b, c = 0, 0, 1
    m = 0
    while m < n:
        yield a
        a, b, c = b, c, (a + b + c)
        m += 1

for t in tribonacci(20):
    print t [/crayon]

この例では、最初の20項を出力している。 実行例:

^o^ > python tribonacci.py
0
0
1
1
2
4
7
13
24
44
81
149
274
504
927
1705
3136
5768
10609
19513

eq?とeqv?とequal?

違いがよくわからなかったのでメモ。

6.2 等価 – Gauche ユーザリファレンス によると次のような違いがある。

eq?

最も高速で、細かい区別ができる述語。 2つの引数がアロケートされる同じ型のオブジェクトで、かつ両者がメモリ上の全く同じ場所を占めるオブジェクトを指している場合に #t を返す。2つの引数がともに文字、あるいは数値だった場合の振るまいは Scheme の標準では定められていない。

gosh> (eq? 'Foo 'Foo)
#t
gosh> (eq? "Foo" "Foo")
#f
gosh> (eq? #\a #\a)
#t
gosh> (eq? 123 123)
#t
gosh> (eq? '(Foo) '(Foo))
#f

Gauche の場合には文字列では #f になるけど、数値では #t になるな。

eqv?

2つの引数 obj1 と obj2 がともに正確な数値、あるいはともに(NaN以外の)不正確な数値である場合、(= obj1 obj2)が真であれば #t が、偽であれば #f が返される。obj1 と obj2 がともに文字である場合、(char=? obj1 obj2)が真であれば #t が、偽であれば #f が返される。それ以外の場合は、Gaucheでは eqv? は eq? と同じ。

gosh> (eqv? 'Foo 'Foo)
#t
gosh> (eqv? "Foo" "Foo")
#f
gosh> (eqv? #\a #\a)
#t
gosh> (eqv? 123 123)
#t
gosh> (eqv? '(Foo) '(Foo))
#f
gosh>

eq? と同じじゃん。正確な数値とか不正確な数値とかがわかんないけど。

equal?

2つに引数 obj1 と obj2 がリストやベクタなどの複合型である場合、equal? は再帰的に対応する要素同士を equal? で比較する。そうでなければ equal? は eqv? と同じようにふるう。

gosh> (equal? 'Foo 'Foo)
#t
gosh> (equal? "Foo" "Foo")
#t
gosh> (equal? #\a #\a)
#t
gosh> (equal? 123 123)
#t
gosh> (equal? '(Foo) '(Foo))
#t

eq? や eqv? では #f になった文字列やリストでも #t になる。

まとめ

表にまとめると次のようになる。

オブジェクト eq? eqv? equal?
シンボル #t #t #t
文字列 #f #f #t
文字 #t #t #t
数値 #t #t #t
リスト #f #f #t

比べるのがシンボルの場合には eq?、文字の場合には eqv?、数値の場合には(上には出てこないけど)=、それ以外は equal? がいいみたいだ。

シンボル型

シンボル型とは、「一言で言うとシンボルとは、文字列をアドレスで管理するデータ型」らしい。

 cf. 12. シンボル型 – もうひとつの Scheme 入門

Ruby のシンボルと同じようなものだと考えてよさそうだ。
シンボルを比較するには、アドレスを比較する eq? が使えるので、高速に比較することができる。なので、連想配列やハッシュ表のキーに使うといいようだ。

今までのエントリに出てきた中では、数値以外のアトムが実はシンボルだった。シンボルを使うにはクォートしてやらないといけない。そうでないと Scheme は変数として評価しようとする。

gosh> foo
*** ERROR: unbound variable: foo
Stack Trace:
_______________________________________
gosh> 'foo
foo

文字列とは違うことに注意。

gosh> (symbol? 'foo)
#t
gosh> (symbol? "foo")
#f

シンボルと文字列は相互に変換できる。文字列からシンボルへは string->symbol、シンボルから文字列へは symbol->string だ。

gosh> (string->symbol "Foo")
Foo
gosh> (symbol->string 'Foo)
"Foo"

処理系にもよるけど、文字列をシンボルに変換するとき小文字にしておかないと、同じつづりでも同じアドレスにならないらしい。

gosh> (eq? (string->symbol "Foo") 'Foo)
#t

同じアドレスでないと、これが #f になるわけだな。Gauche の場合は同じになるようだ。

Pythonで文字列を固定長でスライスする

たまには Python も書かねば。

タイトルのとおりなんだけど、ちょうどいい関数やメソッドが見当たらなかったので書いた。
要するに Ruby の Enumerable#each_slice みたいなのの文字列版。

def string_each_slice(s, n):
    i = 0
    r = []
    while i < len(s):
       r.append(s[i:i+n])
       i += n
    return r

s = "abcdefg"
print string_each_slice(s, 2)
^o^ > python string_each_slice.py
['ab', 'cd', 'ef', 'g']

最後が指定した固定長に足らない場合は、足らないまま返す。まあ、これは Ruby の Enumerable#each_slice と同じ振る舞いにしただけ。