如何在Scheme / LISP中编写all-but-one函数?

时间:2009-12-11 00:12:57

标签: functional-programming lisp scheme

你能想到全功能的最短和最惯用的解决方案吗?

;; all-but-one
;; checks if all but one element in a list holds a certain property
;; (all-but-one even? (list 1 2 4)) -> true
;; (all-but-one even? '(1)) -> true
;; (all-but-one even? '(2 4)) -> false

编辑:完全一个。

8 个答案:

答案 0 :(得分:5)

如果第一个元素具有指定的属性,则在列表的其余部分调用all-but-one

如果第一个元素没有指定的属性,请在列表的其余部分调用all

答案 1 :(得分:4)

名字更好:

(define (all-except-one pred l) (= 1 (count (negate pred) l)))

(但这是PLT特定的。)

答案 2 :(得分:2)

PLT解决方案很优雅,通常我更喜欢使用内置的高阶函数而不是编写自己的递归函数。但是如果你想要一个没有分配且没有算术的有效递归解决方案,那么它就是:

(define (all-but-one pred l)
  (if (null? l) 
     #f
     ((if (pred (car l)) all-but-one all) pred (cdr l))))

递归调用处于尾部位置,因此Scheme和Common LISP都会将此代码编译成紧密循环。有些人可能更喜欢这个等效的代码:

(define (all-but-one pred l)
  (if (null? l) 
     #f
     (if (pred (car l))
        (all-but-one pred (cdr l))
        (all pred (cdr l)))))

答案 3 :(得分:2)

Common Lisp:

(defun all-but-one-p (predicate sequence)
  (= 1 (count-if-not predicate sequence)))

示例:

CL-USER 92 > (all-but-one-p #'evenp '(1 2 3))
NIL

CL-USER 93 > (all-but-one-p #'evenp '(1 2 4))
T

如果多个元素为谓词提供否定结果,则此LOOP版本会提前退出。

(defun all-but-one-p (predicate list)
  (= 1 (loop with not-pred = (complement predicate)
             for item in list count (funcall not-pred item) into counter
             when (> counter 1) do (return-from all-but-one-p nil)
             finally do (return counter))))

答案 4 :(得分:1)

(define (all-but-one p? xs)
  (= (length (filter p? xs)) (- (length xs) 1)))

好的,这个怎么样:不是那么短,而只是一次通过列表。你可以用折叠做同样的事情。

(define (all-but-one p? xs)
  (let loop ((len 0) (sat 0) (tmp xs))
    (if (null? tmp)
        (= sat (- len 1))
        (loop (+ len 1)
              (if (p? (car tmp)) (+ sat 1) sat)
              (cdr tmp)))))

答案 5 :(得分:0)

概括了Anon的想法。

(define (all-but-n n pred lst)
  (if (null? lst)
      (zero? n)
      (if (pred (car lst))
          (all-but-n n pred (cdr lst))
          (if (zero? n)
              #f
              (all-but-n (- n 1) pred (cdr lst))))))

(define (all-but-one pred lst) (all-but-n 1 pred lst))

答案 6 :(得分:0)

应该适用于所有体面的Scheme实现的解决方案:

(define (all-but-one? pred values)

  (define (count-neg x)
    (if (not (pred x)) 1 0))

  (let loop ((c 0) (values values))
    (if (and (not (null? values))
         (<= c 1))
    (loop (+ c (count-neg (car values))) (cdr values))
    (= c 1))))

答案 7 :(得分:0)

(define (all-but-one? p ls)
  (define (all? ls)
    (or (null? ls)
        (and (p    (car ls))
             (all? (cdr ls))))
  (define (loop ls)
    (cond ((null? ls)   #f)
          ((p (car ls)) (all? (cdr ls)))
          (else         (loop (cdr ls)))))
  (loop ls))