File: seqfuncs.lisp

package info (click to toggle)
mcvs 1.0.13-8
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 668 kB
  • ctags: 648
  • sloc: lisp: 5,091; ansic: 223; sh: 190; makefile: 58
file content (91 lines) | stat: -rw-r--r-- 3,474 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
;;; This source file is part of the Meta-CVS program, 
;;; which is distributed under the GNU license.
;;; Copyright 2002 Kaz Kylheku

(require "memoize")
(provide "seqfuncs")

(defun separate-if (test sequence &rest keys)
  (let ((wheat (apply #'remove-if-not test sequence keys))
        (chaff (apply #'remove-if test sequence keys)))
    (values wheat chaff)))

(defun separate (item sequence &key (test #'eql) key)
  (let ((wheat (funcall #'remove-if-not #'(lambda (x) (funcall test item x))
				      sequence :key key))
        (chaff (funcall #'remove item sequence :key key :test test)))
    (values wheat chaff)))

(define-memoized-function lcs-list ((list-1 :test #'eq)
				    (list-2 :test #'eq) 
				    &key (test #'eql))
  (cond
    ((null list-1) nil)
    ((null list-2) nil)
    ((funcall test (first list-1) (first list-2))
       (cons (first list-1) (lcs-list (rest list-1) (rest list-2))))
    (t (let ((lcs-1 (lcs-list list-1 (rest list-2)))
	     (lcs-2 (lcs-list (rest list-1) list-2)))
	 (if (> (length lcs-1) (length lcs-2))
	   lcs-1
	   lcs-2)))))

(defun lcs-vector (vec-1 vec-2 &key (test #'eql))
  (let ((list-1 (coerce vec-1 'list))
	(list-2 (coerce vec-2 'list)))
    (coerce (lcs-list list-1 list-2 :test test) 'vector)))

(defun longest-common-subsequence (seq-1 seq-2 &key (test #'eql))
  (etypecase seq-1
    (list (lcs-list seq-1 seq-2 :test test))
    (vector (lcs-vector seq-1 seq-2 :test test))))

(defun intersection-difference (seq1 seq2 
				&key (key #'values) key1 key2 (test #'eql)
				(combine #'values) squash-nil)
"Finds the intersection, and mutual differences between two sets.
Returns three values: a sequence of elements that are members of seq1 and seq2;
a sequence of elements that are in seq1 only; and a sequence of elements
that are in seq2 only.

Arguments and values:

seq1 seq2       The input sequences.
:key            Monadic function that specifies what part of
                the element of either sequence to extract. By default,
                takes the element itself as the value.
:key1           Override :key value for elements of seq1.
:key2           Override :key value for elements of seq2.
:combine        Dyadic function which specifies how matching elements from seq1 and
                seq2 are combined to form the intersection. The parameters
                to the function are an element from seq1 and a matching
                counterpart from seq2. The default function takes 
                the seq1 element.
:squash-nil     If the combine function returns NIL, do not include the
                value in the intersection set. Default is NIL, do not squash."
  (setf key1 (or key1 key))
  (setf key2 (or key2 key))

  (let ((hash1 (make-hash-table :test test))
	(hash2 (make-hash-table :test test))
	(intersection ())
	(difference1 ())
	(difference2 ()))
    (dolist (i1 seq1)
      (setf (gethash (funcall key1 i1) hash1) i1))
    (dolist (i2 seq2)
      (setf (gethash (funcall key2 i2) hash2) i2)
      (multiple-value-bind (i1 found)
			   (gethash (funcall key2 i2) hash1)
	(if found
	  (let ((combined (funcall combine i1 i2)))
	    (unless (and squash-nil (null combined))
	      (push (funcall combine i1 i2) intersection)))
	  (push i2 difference2))))
    (dolist (i1 seq1)
      (multiple-value-bind (i2 found)
			   (gethash (funcall key1 i1) hash2)
	(declare (ignore i2))
	(unless found
	  (push i1 difference1))))
    (values intersection difference1 difference2)))