2013-06-23 33 views
1

我知道這個問題已被問及之前,我的解決方案是相同的許多答案,但我有一個特殊的測試用例,不能正常工作與這個問題的常見解決方案。計劃壓縮函數與可能不均勻列表

,我已經找到了許多人一樣的zip問題的解決方案是

(define (zip l1 l2)(map list l1 l2)) 

。 。 。其中與給定的參數如

(zip '(a b c) '(1 2 3)) => ((a 1) (b 2) (c 3)) 

,但我也希望壓縮函數來在我的論據並不像

(zip '(a b c) '(1)) => ((a 1) (b()) (c())) 

匹配長度情況下工作的偉大工程,我還沒有找到一個解決這個問題,並不確定如何處理它,每個列表可以是任意長度。

+1

你想做什麼不清楚。您想要的結果沒有正確鍵入:第一個列表由一個符號和一個整數組成,後兩個列表由一個符號和一個列表組成。這是可能的,但不太可能。一個更好的表達式(zip'(a b c)'(1))將返回((a 1))並放棄多餘的項目,或者返回((a 1)(b)(c))。當zip函數有三個或更多的列表時,你會做什麼?請明確說明你想要做什麼。 – user448810

+0

我想要在兩個列表之間進行映射,如果列表是偶數,那麼每個項目都映射到其他列表中項目的相同索引,例如(zip'(abc)'(1 2 3))=>( (a 1)(b 2)(c 3))。我想要但不能產生的附加結果是在兩個給出的參數列表長度不相同的情況下,所以我想要的結果是(zip'(abc)'(1))=>(( a 1)(b())(c()))如果第一個列表中沒有要映射到第二個列表的項目,它只與一個空列表配對,但與當前函數定義不起作用。 – Yoink

回答

1

首先,對於只有2只列出了工作的簡單的迭代版本:

(define (zip lst1 lst2 (placeholder '())) 

    (define (my-car lst) 
    (if (empty? lst) placeholder (car lst))) 
    (define (my-cdr lst) 
    (if (empty? lst) lst (cdr lst))) 

    (let loop ((lst1 lst1) (lst2 lst2) (res '())) 
    (if (and (empty? lst1) (empty? lst2)) 
     (reverse res) 
     (loop (my-cdr lst1) (my-cdr lst2) 
       (cons (list (my-car lst1) (my-car lst2)) res))))) 

(zip '(a b c) '(1 2 3)) 
=> '((a 1) (b 2) (c 3)) 

(zip '(a b c) '(1)) 
=> '((a 1) (b()) (c())) 

這個,你可以概括爲n的列表,但要避免關鍵字參數必須先放置佔位符參數:

(define (zip placeholder . lsts) 

    (define (my-car lst) 
    (if (empty? lst) placeholder (car lst))) 
    (define (my-cdr lst) 
    (if (empty? lst) lst (cdr lst))) 

    (let loop ((lsts lsts) (res '())) 
    (if (andmap empty? lsts) 
     (reverse res) 
     (loop (map my-cdr lsts) 
       (cons (apply list (map my-car lsts)) res))))) 

(zip '() '(a b c) '(1 2 3)) 
==> '((a 1) (b 2) (c 3)) 

(zip '() '(a b c) '(1)) 
==> '((a 1) (b()) (c())) 

(zip '() '(a b c) '(1) '(x y)) 
=> '((a 1 x) (b() y) (c()())) 

我相信andmap是這裏唯一特定拍功能,它可能有一些計劃或SRFI等值積分,取決於您的實現。

編輯

由於該解決方案的基礎是創建等長的名單,而不是複製壓縮算法,也可以先做經典地圖列表東西前添加佔位符列表:

(define (zip placeholder . lsts) 
    (let* ((max-len (apply max (map length lsts))) ; the length of the longest lists 
     (equal-length-lists      ; adjusts all lists to the same length, 
      (map         ; filling with placeholder 
      (lambda (lst) (append lst (make-list (- max-len (length lst)) placeholder))) 
      lsts))) 
    (apply map list equal-length-lists)))  ; classical zip 
+0

我測試了第一個解決方案,它的效果很好,但是您可以如何解釋一下函數定義以及如何獲得佔位符部分?我有點困惑,爲什麼它的結構是這樣。對不起還有新的計劃。 – Yoink

+0

佔位符是zip過程的可選參數;如果你不給任何其他佔位符,那麼將使用'(),如你的例子。現在,因爲在你的情況下,一些列表在循環中最終會變空,而另一些列表仍然有元素,我已經定義了我自己的汽車和cdr程序,而不是扼殺在空列表上,將返回佔位符或'() 。所以我把短列表的長度對齊到最長列表的長度。主循環是一個經典的zip函數,不知道佔位符的內容,只有在處理完所有列表後纔會結束。 – uselpa

+0

非常感謝,現在有了很大的意義。 – Yoink

0

(zip '(a b c) '(1)) =>((a 1) (b()) (c()))(除非您專門使用()作爲佔位符值),它的語義不正確; ((a 1) (b) (c))更合理。下面是實現了一個實現:

(define (zip-with-uneven . lists) 
    (define (advance lst) 
    (if (null? lst) 
     lst 
     (cdr lst))) 
    (define (firsts lists) 
    (let loop ((lists lists) 
       (result '())) 
     (cond ((null? lists) (reverse result)) 
      ((null? (car lists)) (loop (cdr lists) result)) 
      (else (loop (cdr lists) (cons (caar lists) result)))))) 

    (let loop ((lists lists) 
      (results '())) 
    (if (andmap null? lists) 
     (reverse results) 
     (loop (map advance lists) 
       (cons (firsts lists) results))))) 

andmap是從球拍。如果您不使用Racket,則可以使用SRFI 1中的every


如果你真的使用一個佔位符,這裏有一個(具體球拍)版本支持的佔位符。默認的佔位符是(void),我認爲這絕不是您想要放入結果列表中的有效值。

(define (zip-with-uneven #:placeholder (ph (void)) . lists) 
    (define (advance lst) 
    (if (null? lst) 
     lst 
     (cdr lst))) 
    (define (cons-with-placeholder a d) 
    (if (void? a) 
     d 
     (cons a d))) 
    (define (firsts lists) 
    (let loop ((lists lists) 
       (result '())) 
     (cond ((null? lists) (reverse result)) 
      ((null? (car lists)) 
      (loop (cdr lists) (cons-with-placeholder ph result))) 
      (else (loop (cdr lists) (cons (caar lists) result)))))) 

    (let loop ((lists lists) 
      (results '())) 
    (if (andmap null? lists) 
     (reverse results) 
     (loop (map advance lists) 
       (cons (firsts lists) results)))))