2

単語を含むリストを取り込み、「FOO」という単語が見つかった場合にそのリストを 2 つのリストに分割する関数が必要です。私は再帰的な解決策を思いつきました。最善ではないかもしれませんが、少し問題があります。分析するリストである 1 つの引数を渡すだけで済みますが、2 番目のリストを横に作成する方法がわかりません。助言がありますか?ありがとう!

;Splits a list into 2 if the word 'FOO' is present
;----------------------------------------------------------------------
;LOAD FILE: (load "C:\\split.lisp")
;USAGE: (split '(with great power foo comes great responsibility) '())
;OUTPUT: ((with great power)(comes great responsibility))

(defun split (x y)
  (cond
    ( ;IF: first element in list is nil
      (EQ (car x) nil)
        x ;RETURN the list
    )
    ( ;ELSE IF: first element is 'FOO'
      (EQ (car x) 'FOO)
        (cons (reverse y ) (cons (cdr x) nil)) 
    )
    ( ;ELSE: recursively call split but pass the rest of x and 
      ;prepend y with the head of x
      t
        (split (cdr x) (cons (car x) y))
    )
  ) ;END cond
) ;END split
4

4 に答える 4

3

最初のテストは異なるはずです。

以下は本当に良い解決策ではありません: これは末尾再帰ではなく、副作用を使用します。それでも...

(defun split (x)
  (cond ((null x) x)
        ((eq (first x) 'foo)
         (list nil (rest x)))
        (t (let ((l (split (rest x))))
             (push (first x) (first l))
             l))))

上記はPUSHマクロを使用しています。Common Lisp の興味深い機能の 1 つは、場所を使用して変更できることです。この場合、返されるリストの最初のサブリストを変更します。リストの最初の要素を最初のサブリストにプッシュします。

CL-USER 12 > (split '(1 2 3 foo a b c))
((1 2 3) (A B C))

Common Lisp では、通常、非再帰的な方法でソリューションを記述します。

再帰バージョンでは、関数を 1 つの引数に減らす典型的な方法は次のとおりです。1 つの引数で関数を記述し、この関数は 2 つの引数でヘルパー関数を呼び出します。ヘルパー関数は、 を使用してローカルに定義することもできますLABELS

于 2012-09-03T07:48:51.013 に答える
2

リストだけを使用して、これについての私の見解は次のとおりです。

(defun split (lst)
  (labels ((split-rec (lst a)
    (cond
      ((or (null lst)
           (eq (car lst) 'foo))
             (values (reverse a) (cdr lst)))
      (t (split-rec (cdr lst) (cons (car lst) a))))))

    (split-rec lst ())))

splitほとんどの作業をsplit-rec(呼び出しで定義されたlabels) にオフロードし、リストの最後に到達するか、'foo. その時点で、すぐにリストの残りを取得し、それを 2 番目のリストとして扱います。最初のリスト (a) は再帰的に構築されているため、split-rec はそれを返す前に逆にする必要があります。

以下は、REPL のいくつかの実行です。

> (split '(with great power foo comes great responsibility))
(WITH GREAT POWER) ;
(COMES GREAT RESPONSIBILITY)

> (split '(with great power comes great responsibility))
(WITH GREAT POWER COMES GREAT RESPONSIBILITY) ;
NIL

> (split nil)
NIL ;
NIL

> (split '(with great power foo comes great foo responsibility) :on 'foo)
(COMES GREAT) ;
(WITH GREAT POWER RESPONSIBILITY)

> (split '(foo with great power comes great responsibility) :on 'foo)
NIL ;
(WITH GREAT POWER COMES GREAT RESPONSIBILITY)

私が考えることができたエッジケースのほとんどは処理され、2 つのリストが常に返されます。発信者はmultiple-value-bind、両方のリストを取得するために使用できます。つまり、次のようになります。

(multiple-value-bind (a b)
  (split '(with great power foo comes great responsibility))
    ; do something useful with a and b
    )
于 2012-09-27T21:37:20.197 に答える
1
(defun split (lst)
  (let* ((a (make-array (length lst) :initial-contents lst))
         (index (position 'foo a)))
    (cond ((null index) a)
          (t (cons (loop for i from 0 to (1- index)
                      collect (aref a i))
               (list (loop for i from (1+ index) to (1- (length a))
                        collect (aref a i))))))))
  • 要素に簡単にアクセスできるように、リストから配列を作成します。
  • インデックスがマークされている場合は、foo が存在するかどうかを確認します
  • loop を使用して、foo の前の要素と foo の後の要素の 2 つのリストを作成し、それらをまとめます。
于 2012-09-03T13:19:07.797 に答える
0

こちらもやってみました!:)

ただし、明確にしたいことが1つあります。次のようなまれなケースfooでは、リストの最初の要素である場合、2つのリストを返す必要がありますか、それとも2番目のリストのみを返す必要がありますか? fooがリストの最後の要素である場合、リストnilまたは最初のリストのみを返す必要がありますか? リストにない場合fooは、リストだけを返すか、リストとnil/nilとリストを返す必要がありますか?

(defun split (list &key (on-symbol 'foo))
  (let (result result-head)
    (mapl
     #'(lambda (a)
         (if (eql (car a) on-symbol)
             (return-from split
               (if result
                   (values result (copy-list (cdr a)))
                   (copy-list (cdr a))))
             (if result
                 (setf (cdr result-head) (list (car a))
                       result-head (cdr result-head))
                 (setf result (list (car a))
                       result-head result)))) list) result))

(split '(1 2 3 4 5 foo a b c))
(split '(foo 1 2 3 4 5 foo a b c))
(split '(1 2 3 4 5 a b c))
于 2012-09-04T20:03:46.483 に答える