2015-09-20-01-STL書籍の掲載コードをCL-STLで書いてみよう-2
>> Site top >> weblog >> 月別アーカイブ >> 2015年09月のlog >> 2015-09-20-01-STL書籍の掲載コードをCL-STLで書いてみよう-2
最終更新日付:2015/09/20 01:00:00
STL書籍の掲載コードをCL-STLで書いてみよう-2
2015 年 09 月 20 日
昨日に引き続き、Scott Meyers の「Effective STL」から。今回は、第9項の「消去オプションは注意して選択しよう」のコードを CL-STL で書いてみようと思う。
お題は以下の通り。
- コンテナから要素を削除する方法はコンテナの種類によって異なり、すべてのコンテナで動く単一の方法は存在しない。
‥‥‥というわけだ。最初は、連続メモリコンテナから特定の値を削除する方法で、remove アルゴリズムと erase メソッドを使用したイディオムを使えというもの。STL コードは以下の通りだった。c はコンテナだ。
c.erase( std::remove( c.begin(), c.end(), 1963 ), c.end() );
リストの場合も同じ方法が使えるが、remove メソッドを使用した方が効率がいい。双方向チェインの繋ぎ替えのコストだけだからという理由だろう。
c.remove( 1963 );
で、これが CL-STL でどうなるか。こうなる。前回同様、実際にコンテナ c を作成し、結果を出力している。
* (let ((c (new stl:deque #{453 1963 246 9231 1963 1438}))) (stl:erase c (stl:remove (stl:begin c) (stl:end c) 1963) (stl:end c)) (stl:for (v c) (format t " ~A" v))) ;=> 453 246 9231 1438 ; NIL
stl:list ならこうだ。
* (let ((c (new stl:list #{453 1963 246 9231 1963 1438}))) (stl:remove c 1963) (stl:for (v c) (format t " ~A" v))) ;=> 453 246 9231 1438 ; NIL
次に連想コンテナ。erase メソッドを使えば対数時間しかかからない。
c.erase( 1963 );
では CL-STL。話が簡単になるので今回は stl:multiset を使うことにした。
* (let ((c (new stl:multiset #{453 1963 246 9231 1963 1438} #'<))) (stl:erase c 1963) (stl:for (v c) (format t " ~A" v))) ;=> 246 453 1438 9231 ; NIL
では、次へ行こう。今度は特定の値でなく、述語を満足する要素を除去する。関数 badValue があるものとして、前述の std::remove 呼び出しを std::remove_if に置き換える。
bool badValue( int x ); c.erase( std::remove_if( c.begin(), c.end(), badValue ), c.end() );
std::remove_if への置き換えでよいのは c が std::list の場合も同様だ。
c.erase( badValue );
さて、これらを CL-STL コードに変換しよう。実際に動かしたいので、以下のように 3 の倍数かどうかを検査する関数を用意する。
(defun bad-value (x) (zerop (mod x 3)))
で、今度もやることは似たようなモノだ。以下の通り。
* (let ((c (new stl:deque #{0 1 2 3 4 5 6 7 8 9}))) (stl:erase c (stl:remove-if (stl:begin c) (stl:end c) #'bad-value) (stl:end c)) (stl:for (v c) (format t " ~A" v))) => 1 2 4 5 7 8 NIL
stl:list も同様。
* (let ((c (new stl:list #{0 1 2 3 4 5 6 7 8 9}))) (stl:remove-if c #'bad-value) (stl:for (v c) (format t " ~A" v))) => 1 2 4 5 7 8 NIL
おっと、ラムダ式を渡すのが簡単な Lisp なんだから、以下のようなのも載せておかないと。
* (let ((c (new stl:deque #{0 1 2 3 4 5 6 7 8 9}))) (stl:erase c (stl:remove-if (stl:begin c) (stl:end c) (lambda (v) (zerop (mod v 3)))) (stl:end c)) (stl:for (v c) (format t " ~A" v))) => 1 2 4 5 7 8 NIL
第9項の「消去オプションは注意して選択しよう」は、この後 remove-if 的な削除を連想コンテナに対して実質する話に移っていくのだけれど、それは次回以降にしよう。
コメント
このページのタグ
Page tag : STLとその移植
Page tag : Common Lisp
Copyright(C) 2005-2019 project-enigma.
Generated by CL-PREFAB.