スキーム言語のリストに入力されたインデックスの2 つの要素を切り替える必要があります。例えば:
(スワップインデックス 0 3 '(1 2 3 4 5))
(4 2 3 1 5)
誰か助けてくれませんか?前もって感謝します!:)
現時点では、リスト全体を 3 回反復せずにこれを解決する方法は考えられません (それぞれlist-ref
に 1 回、 にもう 1 回build-list
)。最も効率的な解決策ではありませんが、次のようになります。
(define (swap-index idx1 idx2 lst)
(define (build-list lst idx e1 e2)
(cond ((null? lst)
'())
((= idx idx1)
(cons e2 (build-list (cdr lst) (add1 idx) e1 e2)))
((= idx idx2)
(cons e1 (build-list (cdr lst) (add1 idx) e1 e2)))
(else
(cons (car lst) (build-list (cdr lst) (add1 idx) e1 e2)))))
(build-list lst 0 (list-ref lst idx1) (list-ref lst idx2)))
指定されたリストのインデックスが存在すると仮定しています。そうでない場合list-ref
、エラーが発生します。インデックスは任意の順序で渡すことができます。idx1
つまり、より小さい、等しい、またはより大きいことができますidx2
。期待どおりに機能し、変更を加えた新しいリストを返します。
(swap-index 0 3 '(1 2 3 4 5))
=> '(4 2 3 1 5)
このメソッドは、リストを最大 2 回トラバースします。
(define (swap-index index1 index2 lst)
;; FIND-ELEMENTS --
;; INPUT: count, an integer; lst, a list
;; OUTPUT: a pair of the form '(a . b)
(define (find-elements count lst)
(cond ((null? lst) '()) ; really, we should never reach this if indices are valid
((= count index1) ; found the first element, so hold on to it while we look for the next one
(cons (car lst) (find-elements (+ 1 count) (cdr lst))))
((= count index2) (car lst)) ; found the second element, return part 2 of the pair
(else ; since we only care about 2 elements we can just skip everything else
(find-elements (+ 1 count) (cdr lst)))))
;; BUILD-LIST --
;; INPUT: count, an integer; elements, a pair; lst, a list
;; OUTPUT: a new list
(define (build-list count elements lst)
(cond ((null? lst) '()) ; again, we shouldn't get here if indices are valid
((= count index1) ; reached first index, substitute 2nd element and keep going
(cons (cdr elements) (build-list (+ 1 count) elements (cdr lst))))
((= count index2) ; reached second index, substitute 1st element and stop
(cons (car elements) (cdr lst)))
(else ; everything else just gets added to the list per usual
(cons (car lst) (build-list (+ 1 count) elements (cdr lst))))))
(build-list 0 (find-elements 0 lst) lst)) ; call build-list using a call to find-elements as a parameter
まず、リストを調べて、交換したい要素のペアを find-elements
返します。注: このコードは、最小のものが最初になるようにインデックスが順番に与えられているという前提に依存しています。cons
次に、build-list
からの出力をfind-elements
取得して、次の走査中に適切な要素を置き換えることができるようにします。
これがclojureの解決策です。アルゴリズムが役立つことを願っています。
(defn split [idx lst]
(let [lst-rest (drop idx lst)]
[(take idx lst) (first lst-rest) (rest lst-rest)]))
(defn swap-index [idx1 idx2 lst]
(let [[lst1 e1 lst] (split idx1 lst)
[lst2 e2 lst3] (split (dec (- idx2 idx1)) lst)]
(concat lst1 [e2] lst2 [e1] lst3)))
=> (swap-index 0 3 [1 2 3 4 5])
(4 2 3 1 5)