2013-07-16 30 views
5

基本上返回任何東西,我想用地圖做選擇列表中的像不從LISP /計劃

(define tbl '(a b c d)) 
(map (lambda (item 'c) (if (eq? item 'c) item (...what in else?)))) 

我想要的結果是

'(c) 

我試圖離開else部分空,它抱怨說其他部分是需要的。 我試圖

(display "foo") 

的其他部分,並得到

(#<void> #<void> C#<void>) 

也就是說接近。

有沒有什麼方法可以用map來得到'(c)?我知道遞歸的方式,但我想知道如果地圖可以做到這一點。如果不是'(c),至少(##c#)但不使用顯示黑客來實現無效類型的返回值。


+0

順便說一句:作爲參數傳遞給'map'了'lambda'必須接收_single_參數,你傳遞兩個將無法工作:'(項目「C )' –

+0

你在用什麼解釋器?我的猜測是Racket,但請確認 –

+1

@ÓscarLópez,是的,它是Racket,但我希望解決方案可以是普遍的 –

回答

12

你想用filter,不map - 因爲輸出列表將可能具有比輸入列表中少的元素。通過display返回所有這些#<void>值是有,因爲map總是包含在輸出列表中的結果,甚至那些我們不感興趣的元素

(define tbl '(a b c d)) 

(filter (lambda (item) (eq? item 'c)) tbl) 
=> '(c) 

等價的,又有點短。

(filter (curry eq? 'c) tbl) 
=> '(c) 

map用於您希望對輸入列表中的每個元素執行某些操作而不丟棄元素。另一方面,filter用於在輸入列表中選擇一些的元素,對於給定的謂詞則評估爲#tfilter在大多數Scheme解釋器中可用,如果它不可用,則可以導入SRFI-1或使用reference implementation

有沒有辦法使用獲得'(c)map(它可以使用mapapplyremove*等,被黑客入侵,但是這不是想法,是嗎?);如果由於某種原因,你必須只使用map,不介意與返回佔位符列表,這裏有幾個選擇:

(map (lambda (item) (if (eq? item 'c) item '%)) tbl) ; placeholder in else part 
=> '(% % c %) 

(map (lambda (item) (when (eq? item 'c) item)) tbl) ; when has implicit #<void> 
=> '(#<void> #<void> C#<void>) 

時間一點點的黑客。使用mapapply(如@WillNess的回答解釋),這在任何RxRS解釋工作的優勢,是目前最便攜的解決方案,因爲它使用了標準程序:

(apply append (map (lambda (item) (if (eq? item 'c) (list item) '())) tbl)) 
=> '(c) 

使用mapremove*

(remove* (list (void)) (map (lambda (item) (when (eq? item 'c) item)) tbl)) 
=> '(c) 

對於改變,沒有map溶液 - 使用foldr代替:

(foldr (lambda (item a) (append (if (eq? item 'c) (list item) '()) a)) '() tbl) 
=> '(c) 

當然,你總是可以實現只用標準程序你的filter自己的版本,這也將是可跨所有RxRS解釋:

(define (filter pred? lst) 
    (cond ((null? lst) 
     '()) 
     ((not (pred? (car lst))) 
     (filter pred? (cdr lst))) 
     (else 
     (cons (car lst) 
       (filter pred? (cdr lst)))))) 

(filter (lambda (item) (eq? item 'c)) tbl) 
=> '(c) 
+0

爲了更好地理解'map'和'filter'過程的推薦閱讀:[作爲傳統接口的序列](https://mitpress.mit.edu/ (SICP)(https://mitpress.mit.edu/sicp/full-text/book/book.html)中的sicp/full-text/book/book-ZH-15.html#%_ sec_2.2.3) –

+1

如果您的實現缺少咖喱功能,但支持SRFI-26,則可選擇(過濾(cut eq?'c <>)tbl)。對於任何想深入挖掘的人來說,map和filter都可以使用fold來實現。 –

+0

'#':另一個'nil'的碎片,在Scheme中被破壞。什麼是聚類funk。 「不知何故,我更喜歡(CDR(ASSQ KEY A-LIST))」 - Ashwin Ram – Kaz

1

你沒有提到你的計劃版本/環境。假設你只需要最基本的計劃,這是很容易實現的東西:

(define (choose-if pred list) 
    (let choosing ((list list) (rslt '())) 
    (if (null? list) 
     (reverse rslt) 
     (choosing (cdr list) 
        (if (pred (car list)) 
         (cons (car list) rslt) 
         rslt))))) 

,然後相關:

(define (choose item list) 
    (choose-if (lambda (elt) (eq? item elt)) list)) 

(define (choose-if-not pred list) 
    (choose-if (lambda (elt) (not (pred elt))) list)) 

及用途:

> (choose 'c '(a b c d)) 
(c) 

您也可以選擇使用低級基元:

(define (choose item list) 
    (remq #f (map (lambda (elt) (eq? item elt)) list))) 

(define (choose item list) 
    (remp (lambda (elt) (not (eq? item elt))) list)) 
3

的簡單的 「標準」 特技是

(apply append (map (lambda(x)(if (eq? x 'c) (list x) '())) '(a b c d))) 
;Value 12: (c) 

返回(c)。該apply append ... map組合體被稱爲Common Lisp中mapcan(「mapcan」爲「地圖並連接」):

[1]> (mapcan #'(lambda(x)(if (eq x 'c) (list x))) '(a b c d)) 
(C) 

麻省理工學院計劃有這個功能了。

apply append拉平它的參數列表中的一個級別,(apply append '((a)() (c)()))==(append '(a) '() '(c) '())- >(a c)。由於空列表消失,因此用於消除map中的元素很有用。如果您有一個可用(它不在R5RS中,但它在SRFI1中),則達到與filter相同的效果。

它可以用於其他效果太像加倍:

[2]> (mapcan #'(lambda(x)(if (evenp x) (list x x))) '(1 2 3 4)) 
(2 2 4 4) 

順便說一句,mapcan是什麼作爲列表單子的「綁定」(帶有參數翻轉),並(apply append ...)爲「加入」操作。事實上,它必須適用於任何monad,對於列表bind m f == join (map f m)

這也是例如Haskell的列表內涵

Prelude> [y | x<-[1,2,3,4], even x, y<-[x,x]] 
[2,2,4,4] 
+0

'mapcan'的等效球拍是'append-map'。 –