- リストの要素を置き換えたいけど、どうすればいい?
- substの使い方がよくわからない
- 同じ要素が複数あるとき、全部置き換えられて困る
リストの要素を変えたいけど、どうすればいいかわからずお困りではないでしょうか。substを試してみたけど、使い方がよくわからず戸惑うこともありますよね。
私はAutoLISPを独学し、業務の自動化・効率化に役立つプログラムを5年以上作成しています。数行で書けるような簡単なプログラムから、1000行以上の少し複雑なプログラムまで様々なツールを作成してきました。
そもそもAutoLISPってなに?という方はこちらの記事をご覧ください。
>>AutoCADユーザー必見!【AutoLISPを覚えるべきメリット5選】デメリットも解説
当記事ではリストの要素を置き換えるAutoLISP関数「subst」の使い方やポイントを初心者向けに解説します。さらに、リストのn番目だけを置き換えるプログラムも合わせてご紹介。
リスト操作をラクにして毎日の作業を少しでも効率化したい方は、ぜひ最後までお読みください。
あなたに代わってAutoLISPプログラムを作成します
AutoLISPで作業を自動化したいけど、プログラミングに詳しくないのでツールが作れずにお悩みの方へ。5年以上のAutoLISP経験を活かしてAutoCADを自動化するツールを作成します。既にお持ちのAutoLISPプログラム修正も対応可能です。
AutoCADの面倒くさい作業から解放されたい方は、下記リンク先の「ココナラ」からお気軽にご相談ください。
>>AutoCADが楽になるプログラムを作成します|ココナラ
最短2日で納品します
リストの要素を置き換えるAutoLISP関数「subst」

今回はAutoLISP関数のsubstについて解説します。substは書き方がシンプルで操作も直感的。初心者にも扱いやすく、リスト編集の基本として知っておくと便利な関数です。

substの特徴や使い方について詳しく解説していきます。
初心者が覚えておきたいsubstの使い方と特徴4選

substには以下のような特徴があります。
- 指定の値と完全に一致する要素をすべて置き換える
- 入れ子の要素は置き換えできない
- 一致する要素がない場合は元のリストがそのまま返り値となる
substはリスト内で指定の値と完全に一致する要素をすべて置き換えます。たとえば、以下のリストで1を4に置き換えると、リスト内の1が2つとも4に置き換わります。
(subst 4 1 (list 1 2 1 3)) ; → (4 2 4 3)
ちなみに、要素がリストであっても置き換えは可能です。
(subst (list 2 3) (list 1 2) (list (list 1 2) (list 1 3))) ; → ((2 3) (1 3))
ただし、上記のようなリストの中にさらにリストが入っている入れ子構造では、引数と同じ値であっても中のリストまでは置き換えができません。たとえば以下の場合、1は4に置き換わらないので注意してください。
(subst 4 1 (list (list 1 2) (list 1 3))) ; → ((1 2) (1 3))

置き換わるのは、あくまで完全に一致する要素だけです。
置きかえたい値がリストの中にないときは、元のリストがそのまま返ります。エラーになったり、空リストになることはありません。
(subst 5 1 (list 1 2 1 3)) ; → (1 2 1 3)
substは使い方のルールを知っておけば、安全にリストを操作できる便利な関数です。まずはシンプルな例から試して、少しずつ慣れていきましょう。
リストのn番目要素だけ置き換えるプログラム

前述したようにsubstはリスト内の要素を置き換えることができます。しかし、リスト内に置き換えたい要素と同じ要素が複数ある場合、substの機能だけでは1つ(n番目)の要素のみ置き換えることはできません。
そこで今回はリストのn番目要素だけ置き換える専用のプログラムをご紹介します。比較的シンプルなプログラムを用意しましたので、ぜひ参考にしてください。
プログラムと動作解説
リストのn番目要素だけ置き換える専用のプログラムは以下のとおりです。
;; リストのn番目要素だけ置き換える
(defun replace_nth (lst n new)
(if (or (< n 0) (>= n (length lst)))
lst ;; 範囲外なら元のリストを返す
(cons
(if (= n 0) new (car lst))
(if (= n 0) (cdr lst) (replace_nth (cdr lst) (1- n) new))
)
)
)
replace_nthはリストの中のn番目(0から数える)の要素を新しい値に置き換えるための関数です。使用している変数の内容は次のようになっています。
- lst:対象となるリスト
- n:置き換えたい位置(0から始まる要素番号)
- new:新しく入れたい値
使用しているAutoLISP関数については下表をご覧ください。
使用している関数 | 内容 | 解説記事リンク |
defun | ユーザー関数を定義する | 詳細を見る |
if | 条件分岐を行う | 詳細を見る |
cons | ドット対(コンスセル)を作成する | 詳細を見る |
car、cdr | リストから要素を取り出す | 詳細を見る |

処理の流れを順番に解説していきます。
① 範囲外チェック
(if (or (< n 0) (>= n (length lst)))
lst
...
)
nが0未満(負の数)だったり、リストの要素数以上だった場合は、「その位置には要素がない」と判断して元のリストをそのまま返します。
② 要素の置き換え(再帰的に処理)
(cons
(if (= n 0) new (car lst))
(if (= n 0) (cdr lst) (replace_nth (cdr lst) (1- n) new))
)
上記の部分が今回のプログラムで一番重要なポイントです。
n=0 なら、その場所が「置き換えたい位置」なので、(car lst)をnewに置き換えて、(cdr lst)はそのまま使います。n≠0の場合、(car lst)はそのままで、(cdr lst)に対してさらにreplace_nth関数を繰り返します。
関数の中で自身と同じ関数を呼び出す処理を再帰処理と呼びます。再帰処理についてもっと知りたい方はこちらを参考にしてください。
>>再帰処理とは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

繰り返しの中でnを1ずつ小さくしているところもポイントです。
プログラムの使用例
たとえば、(1 1 2 3)というリストで先頭から2番目の要素だけ、4に置き換えたい場合は以下のように書きます。
(setq lst (list 1 1 2 3))
(replace_nth lst 4 1)
;; → (1 4 2 3)

リストの要素番号は0から始まるので、先頭から2番目の要素番号は1です。
ご紹介したプログラムを使えば、リストのn番目だけを簡単に置き換えられます。細かいリスト操作に便利なので、ぜひ活用してみてください。
substを使いこなしてリスト操作の幅を広げよう

今回ご紹介したsubstについて以下にまとめます。
関数 | 内容 | 使用例 |
subst | リスト内で指定の値と 完全に一致する要素を置き換える | (subst 5 1 (list 1 2 3 4)) ; → (5 2 3 4) |
リスト内に置き換えたい要素と同じ要素が複数ある場合、substで置き換えようとすると同じ要素がすべて置き換わってしまいます。n番目の要素だけ置き換えたいときは、専用のプログラムを作成してください。
substの使い方を押さえれば、リスト操作がぐっとスムーズになります。当記事を参考に、実際のプログラムで試してみてください。