基本上,我想使用map在列表中进行选择,如
(define tbl '(a b c d))
(map (lambda (item 'c) (if (eq? item 'c) item (...what in else?) )))
我想要的结果是
'(c)
我试着把其他部分保持为空,它抱怨说其他部分是必需的。我试过了
(display "foo")
因为其他的部分
(#<void> #<void> c #<void>)
差不多了。
我能用地图得到'(c)‘吗?我知道递归的方法,但我想知道map是否也能做到这一点。如果不是'(c),至少(# #c #),但不使用显示黑客来实现空类型返回值。
发布于 2013-07-16 15:31:13
您希望使用filter
,而不是map
,因为输出列表可能比输入列表有更少的元素。所有由#<void>
返回的display
值都存在,因为map
总是在输出列表中包含一个结果,即使对于那些我们不感兴趣的元素也是如此。
(define tbl '(a b c d))
(filter (lambda (item) (eq? item 'c)) tbl)
=> '(c)
相当于,而且更短一点:
(filter (curry eq? 'c) tbl)
=> '(c)
当您想要对输入列表中的每个元素做一些事情时,使用map
,而不丢弃元素。另一方面,filter
用于选择输入列表中的一些元素,那些为给定谓词计算到#t
的元素,而filter
在大多数Scheme解释器中都是可用的,如果它不可用,则可以导入SRFI-1
或使用参考实施。
没有办法只使用'(c)
来获得map
(可以使用map
+ apply
或remove*
等攻击它,但这不是这个想法吗?);如果出于某种原因,您必须只使用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>)
是时候做点黑客了。使用map
+ apply
(如@WillNess的答案中所解释的),它具有在任何RxRS解释器中工作的优点,并且是最可移植的解决方案,因为它使用的是标准过程:
(apply append (map (lambda (item) (if (eq? item 'c) (list item) '())) tbl))
=> '(c)
使用map
+ remove*
(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)
发布于 2013-07-19 08:47:34
简单的“标准”技巧是
(apply append (map (lambda(x)(if (eq? x 'c) (list x) '())) '(a b c d)))
;Value 12: (c)
返回(c)
。apply append ... map
组合体在通用Lisp中被称为mapcan
("mapcan“表示"map和concatenate"):
[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
消除元素很有用。如果您有一个可用的filter
(它不在R5RS中,但在SRFI1中),这将实现与SRFI1相同的效果。
它也可以用于其他效果,如加倍:
[2]> (mapcan #'(lambda(x)(if (evenp x) (list x x))) '(1 2 3 4))
(2 2 4 4)
顺便说一句,mapcan
是list monad的"bind“(带参数翻转),(apply append ...)
是它的”联接“操作。事实上,对于任何一个单子,列表也是如此,bind m f == join (map f m)
也是如此。
这也是Haskell的清单理解的基础:
Prelude> [y | x<-[1,2,3,4], even x, y<-[x,x]]
[2,2,4,4]
发布于 2013-07-16 20:43:52
您没有提到您的计划版本/环境。假设您只有最基本的方案,那么很容易实现:
(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))
https://stackoverflow.com/questions/17680799
复制相似问题