AutoLISP関数 関数解説

リストの要素を取り出す基本!AutoLISP関数のcarとcdrを徹底解説

carcdr_eyecatchpng

AutoLISPを使い始めたけれど、「リストの扱いがよくわからない…」と感じていませんか?そんな方にぜひ知ってほしいのが、リストの基本を支える関数「car」と「cdr」です。

私はAutoLISPを独学し、業務の自動化・効率化に役立つプログラムを5年以上作成しています。数行で書けるような簡単なプログラムから、1000行以上の少し複雑なプログラムまで様々なツールを作成してきました。

そもそもAutoLISPってなに?という方はこちらの記事をご覧ください。
>>AutoCADユーザー必見!【AutoLISPを覚えるべきメリット5選】デメリットも解説

一見むずかしそうに見えますが、ポイントを押さえればとてもシンプル。当記事ではcarとcdrとは何か、どうやって使うのかをやさしく解説します。

リスト操作のコツをつかめば、AutoLISPでの作業がぐっとスムーズになります。AutoLISPで業務を効率化したい方はぜひ最後までお読みください。

あなたに代わってAutoLISPプログラムを作成します

AutoLISPで作業を自動化したいけど、プログラミングに詳しくないのでツールが作れずにお悩みの方へ。5年以上のAutoLISP経験を活かしてAutoCADを自動化するツールを作成します。既にお持ちのAutoLISPプログラム修正も対応可能です。

AutoCADの面倒くさい作業から解放されたい方は、下記リンク先の「ココナラ」からお気軽にご相談ください。
>>AutoCADが楽になるプログラムを作成します|ココナラ

リストはcarとcdrで成り立つ!AutoLISPのリスト構造を解説

carcdr_caption1

AutoLISPのリストは「先頭の要素」と「残りの要素」の2つに分かれており、「先頭の要素」を「car」、「残りの要素」を「cdr」と呼びます。この”2つのパーツ”の繰り返しがリスト構造の基本です。

リストは単に複数の値を並べただけのデータではありません。「car部」と「cdr部」の2つの要素をペアにした形(ドット対)で構成されています。

ドット対とは、ドット(.)で区切られた2つの値をペアにして保持する構造のこと。このペアが連続してつながることで、複数の要素を持つリスト全体が形成されます。

ちなみにリストとドット対を作成するAutoLISP関数について知りたい方は、こちらの記事をご覧ください。
>>【初心者必読】リストを作成するAutoLISP関数3選|使用例も解説

はこさん。
はこさん。

ドット対はコンスセルとも呼ばれます。

たとえば、(1 2 3)というリストの場合、リスト全体のcar部は1で、cdr部は(2 3) のリストです。

  • car部 → 1
  • cdr部 → (2 3)

さらに、cdr部である(2 3)に対しても同じように分解を行うと、car部は2、cdr部は(3)となります。

  • car部 → 2
  • cdr部 → (3)
はこさん。
はこさん。

(3)は要素が1つだけのリストです。

そして、(3)を分解するとcar部は3、cdr部はnilになっています。最後のcdr部は中身が空なので、リストではなくnilとなる点に注意してください。

  • car部 → 3
  • cdr部 → nil

上記のリスト構造をドット対で表現すると次のようになります。

(1 . (2 . (3 . nil)))

リストの中身を「先頭」と「残り」に分けると、AutoLISPのリスト構造が見えてきます。考え方を覚えるとリストの操作がずっとわかりやすくなるので、ぜひ頭の片隅に置いてみてください。

リストの要素を自在に取り出すAutoLISP関数2選

carcdr_caption2

今回ご紹介するAutoLISP関数は以下の2つです。

  • car
  • cdr

名前のとおり、前述したcar部とcdr部を取り出すことができます。どちらもリストの要素を取り出す基本的な関数なので、しっかりマスターしましょう。

はこさん。
はこさん。

順番に解説していきます。

car 先頭の要素を取り出す

carcdr_car

carはリストの先頭要素である、car部を取り出すAutoLISP関数です。carには次のような特徴があります。

  • リスト(ドット対)の最初の要素を返す
  • 空のリスト(nil)を与えた場合はnilを返す
  • リスト(ドット対)以外ではエラーになる

carは引数として与えられたリスト(ドット対)の先頭要素を返します。たとえば、次のように使用してください。

(car (list A B C)) ; → A

上記の場合、返り値はAです。carは常に、先頭の1つだけを返す特徴があります。リストの2番目以降が必要な場合は、後述するcdrやcadrなどと組み合わせて使ってください。

また、carに空のリスト(nil)を与えたときの返り値はnilです。以下のようなプログラムでもcarはエラーにはなりません。

(car nil) ; → nil

ちなみに、AutoLISPではnilがリストの終端を表す特別な値として扱われています。carはリストの終端(nil)をそのまま返す仕様のため、nilを含んだ条件分岐や再帰処理に活かせます。

AutoLISPの条件分岐についてもっと知りたい方はこちらの記事をご覧ください。
>>【初心者向け】処理を自由に切り替えよう!条件分岐のAutoLISP関数2選

carはリスト(ドット対)を前提とした関数なので、引数がリストでないとエラーになります。数値や文字列に対して使うとエラーになるので注意してください。

(car 123)   ; → エラー
(car "abc") ; → エラー
はこさん。
はこさん。

listp関数などでデータの型をしっかり確認しておくと、エラーの予防につながります。

car自体はシンプルな関数ですが、リストのしくみを理解するうえでとても大切な役割を持っています。最初はむずかしく感じるかもしれませんが、少しずつ触れて理解を深めていきましょう。

cdr リストの先頭要素以外を取り出す

carcdr_cdr

cdrはリストの先頭要素以外である、cdr部を取り出すAutoLISP関数です。cdrの特徴は以下のとおり。

  • リスト(ドット対)の先頭要素を除いた「残り」を返す
  • 空のリスト(nil)を与えた場合はnilを返す
  • リスト(ドット対)以外ではエラーになる

cdrは引数としてリスト(ドット対)を与えると、先頭要素を取り除いた「残り」を返します。たとえば、次のように使用します。

(cdr (list A B C)) ; → (B C)

上記のときに返されるのは(B C)です。carが「先頭の要素」を返すのに対し、cdrはその後ろに続くリスト全体を返します。要素が1つだけのリストの場合は、リストの終端であるnilが返り値となります。

(cdr (list A)) ; → nil
はこさん。
はこさん。

cdrがnilを返せば、リストの終端と判断することができます。

また、与えられたリストが空(nil)であっても、cdrを使うことは可能。carと同様にnilを返すので、条件分岐や再帰処理で役立ちます。

(cdr nil) ; → nil

cdrはリスト(ドット対)を対象として関数なので、数値や文字列などリスト以外の値を与えるとエラーになります。

(cdr 100)     ; エラー
(cdr "abc")   ; エラー
はこさん。
はこさん。

安全に使いたいときは、listp関数などでリストかどうかを事前にチェックしてください。

cdrはリストを分解したり、要素を順に処理したりする場面でよく使われます。シンプルな関数ですが、リスト構造を理解するカギになるので、基本をしっかりおさえておきましょう。

任意の要素を取り出そう!carとcdrの組み合わせ関数一覧

リストから要素を取り出すときは、前述したcarとcdrを使うのが基本です。しかし、2番目や3番目の要素を取り出したいとき、carとcdrを何度も書くことになるのでプログラムが読みづらくなりがち。

そこで、AutoLISPにはcarとcdrを組み合わせて、1つにした関数が用意されています。たとえば、次のようなリストがあるとします。

(setq lst (list (list A B) (list C D) (list E F)))

以下のように書くと、2番目の要素である(C D)を取り出すことが可能。

(cadr lst) ; → (C D)

cadrは (car (cdr lst)) を短く書いたものです。「リストの先頭を1つスキップ(cdr)、次の要素を取り出す(car)」という意味になります。

さらに、2番目の要素から「C」を取り出す場合は次のように書いてください。

(caadr lst) ; → C
はこさん。
はこさん。

取り出したい要素がどこにあるか、確認しておくことが重要です。

carとcdrの組み合わせ関数一覧

AutoLISPに用意されているcarとcdrを組み合わせた関数は以下のとおりです。4段階の深さまでしか用意されていないので、5段階以上の要素を取り出したいときはnthを使ってください。

nthはリストからn番目の要素を取り出すAutoLISP関数です。nthについてはこちらの記事で解説しています。
>>【AutoLISP】リストの要素を取得する関数「nth」「last」「assoc」

関数carとcdrでの表記
caar(car (car lst))
cdar(cdr (car lst))
cadr(car (cdr lst))
cddr(cdr (cdr lst))
関数carとcdrでの表記
caaar(car (car (car lst)))
cdaar(cdr (car (car lst)))
cadar(car (cdr (car lst)))
cddar(cdr (cdr (car lst)))
caadr(car (car (cdr lst)))
cdadr(cdr (car (cdr lst)))
caddr(car (cdr (cdr lst)))
cdddr(cdr (cdr (cdr lst)))
関数carとcdrでの表記
caaaar(car (car (car (car lst))))
cdaaar(cdr (car (car (car lst))))
cadaar(car (cdr (car (car lst))))
cddaar(cdr (cdr (car (car lst))))
caadar(car (car (cdr (car lst))))
cdadar(cdr (car (cdr (car lst))))
caddar(car (cdr (cdr (car lst))))
cdddar(cdr (cdr (cdr (car lst))))
関数carとcdrでの表記
caaadr(car (car (car (cdr lst))))
cdaadr(cdr (car (car (cdr lst))))
cadadr(car (cdr (car (cdr lst))))
cddadr(cdr (cdr (car (cdr lst))))
caaddr(car (car (cdr (cdr lst))))
cdaddr(cdr (car (cdr (cdr lst))))
cadddr(car (cdr (cdr (cdr lst))))
cddddr(cdr (cdr (cdr (cdr lst))))
はこさん。
はこさん。

深い要素を取り出す場合はcarとcdrの組み合わせを使うより、nthの方がシンプルでわかりやすいのでおすすめです。

carとcdrを覚えてリスト操作の基本をマスターしよう!

carcdr_caption3

今回の内容を以下にまとめます。

  • AutoLISPのリストは「先頭の要素」と「残りの要素」の2つで構成されている
  • 「先頭の要素」を「car」、「残りの要素」を「cdr」と呼ぶ
  • carはリストのcar部を、cdrはcdr部を取り出すAutoLISP関数
  • AutoLISPにはcarとcdrを組み合わせて1つにした関数が用意されている
関数内容使用例
carリストの先頭要素を取り出す(car (list 1 2 3)) ; → 1
cdrリストの先頭要素以外を取り出す(cdr (list 1 2 3)) ; → (2 3)

carやcdrを使えばリスト操作が効率化されます。cadrなども活用すれば処理がよりスマートに。作図の自動化や業務効率化にもつながるので、ぜひ実務で役立ててください。

AutoCADが楽になるプログラムを作成します AutoCADを効率化して面倒な作業から解放されましょう!

-AutoLISP関数, 関数解説