36

Common Lispで連続番号のリストを作成するにはどうすればよいですか?

言い換えれば、rangeCommon LispのPythonの関数に相当するものは何ですか?

Pythonでは、をrange(2, 10, 2)返します[2, 4, 6, 8]。最初と最後の引数はオプションです。Emacs Lispにはあるが、数列を作成する慣用的な方法を見つけることができなかったnumber-sequence

範囲はループマクロを使用してエミュレートできますが、開始点と終了点、およびステップを持つ数列を生成するための受け入れられた方法を知りたいです。

関連:SchemeでのPythonの範囲のアナログ

4

10 に答える 10

41

一連の数値を生成する組み込みの方法はありません。これを行う標準的な方法は、次のいずれかを行うことです。

  • 使用するloop
  • を使用するユーティリティ関数を作成します。loop

実装例は次のようになります (これは「低」から「高」へのカウントのみを受け入れます):

(defun range (max &key (min 0) (step 1))
   (loop for n from min below max by step
      collect n))

これにより、(オプションの) 最小値と (オプションの) ステップ値を指定できます。

奇数を生成するには:(range 10 :min 1 :step 2)

于 2012-12-18T16:47:51.357 に答える
19

alexandria はスキームの iota を実装しています:

(ql:quickload :alexandria)
(alexandria:iota 4 :start 2 :step 2)
;; (2 4 6 8)
于 2012-12-27T11:35:39.747 に答える
6

これが私が問題に取り組む方法です:

(defun generate (from to &optional (by 1))
  #'(lambda (f)
      (when (< from to)
        (prog1 (or (funcall f from) t)
          (incf from by)))))

(defmacro with-generator ((var from to &optional (by 1)) &body body)
  (let ((generator (gensym)))
    `(loop with ,generator = (generate ,from ,to ,by)
        while
          (funcall ,generator
                   #'(lambda (,var) ,@body)))))

(with-generator (i 1 10)
    (format t "~&i = ~s" i))

しかし、これは単なる一般的な考え方であり、改善の余地がたくさんあります。


OK、ここで議論があるようですので。本当に必要なのはPythonのrangeジェネレーター関数に類似していると思います。これは、ある意味で数値のリストを生成しますが、反復ごとに数値を生成することによって生成します(一度に複数のアイテムが作成されないようにするため)。ジェネレーターはややまれな概念です(いくつかの言語がそれを実装しています)ので、Pythonの言及は、この正確な機能が望ましいことを示唆していると思いました。

上記の私の例に対するいくつかの批判に続いて、単純なループではなくジェネレーターが使用される理由を説明する別の例を次に示します。

(defun generate (from to &optional (by 1))
  #'(lambda ()
      (when (< from to)
        (prog1 from
          (incf from by)))))

(defmacro with-generator
    ((var generator &optional (exit-condition t)) &body body)
  (let ((g (gensym)))
    `(do ((,g ,generator))
         (nil)
       (let ((,var (funcall ,g)))
         (when (or (null ,var) ,exit-condition)
           (return ,g))
         ,@body))))

(let ((gen
       (with-generator (i (generate 1 10) (> i 4))
         (format t "~&i = ~s" i))))
  (format t "~&in the middle")
  (with-generator (j gen (> j 7))
    (format t "~&j = ~s" j)))

;; i = 1
;; i = 2
;; i = 3
;; i = 4
;; in the middle
;; j = 6
;; j = 7

これもまた、この機能の目的を示したものにすぎません。2つのステップで行う必要がある場合でも、整数の生成に使用するのはおそらく無駄ですが、パーサーの以前の状態に基づいて構築されたより複雑なオブジェクトを生成する場合は、ジェネレーターがパーサーに最適です。たとえば、他にもたくさんあります。さて、あなたはここでそれについての議論を読むことができます:http: //en.wikipedia.org/wiki/Generator_%28computer_programming%29

于 2012-12-18T17:52:30.757 に答える
2

開始、停止、ステップを指定する単純な形式:

(defun range (start stop step) 
  (do (
    (i start (+ i step)) 
    (acc '() (push i acc))) 
   ((>= i stop) (nreverse acc))))
于 2016-11-28T00:44:14.287 に答える