2015-09-20-01-STL書籍の掲載コードをCL-STLで書いてみよう-2 - project-enigma

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 08:08:31


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-2017 project-enigma.
Generated by CL-PREFAB.