Reputation: 7556
I am not experienced in LISP and list processing, but I have a set of C++ STL vectors (or strings) on which I need to perform the following operations:
IdenticalHead (v1, v2): Return the biggest sequence that both v1 and v2 start with it.
IdenticalTail (v1, v2): Return the biggest sequence that both v1 and v2 end with it.
IdenticalTailHead (v1, v2): Return the biggest sequence that v1 ends with it and v2 starts with it.
For example:
if v1 = (a,b,c,e,f), v2 = (a,b,d,e,f), then:
IdenticalHead (v1, v2) = (a,b)
IdenticalTail (v1, v2) = (e,f)
if v1 = (a,b,c), v2 = (b,c,g), then:
IdenticalTailHead (v1, v2) = (b,c)
My question is that are these standard operations in LISP or any other language? Do they have standard names like CDR and CAR?
Upvotes: 2
Views: 232
Reputation: 71065
Since you mention "other language", Haskell is a kind-of Lispy language, and it does have idiomatic approach to what you're asking about.
longestPrefix xs ys = map fst (takeWhile (\(x,y) -> x == y) (zip xs ys))
zip
pairs up the elements of its two argument lists, and takeWhile
is self-descriptive.
For the second variant you'd just use reverse
on arguments and on the result. The third is a bit more involved:
longestPrefixEnding xs ys = -- '(a e d b c d) '(b c d a f)
head [t | t <- tails xs, let p=longestPrefix t ys, p==t]
tails xs
is equivalent to iterate tail xs
i.e. the list [xs, tail xs, tail (tail xs), ...]
; tail
is a synonym of cdr
, and head
- synonym of car
:
Prelude Data.List> longestPrefix "abcef" "abdef"
"ab"
Prelude Data.List> longestPrefixEnding "aedbc" "bcdaf"
"bc"
Prelude Data.List> longestPrefixEnding "aebcabcd" "bcdaf"
"bcd"
Prelude Data.List> longestPrefixEnding "aebcabcdx" "bcdaf"
""
Upvotes: 1
Reputation: 139261
IdenticalHead and IdenticalTail are basically provided by the Common Lisp function MISMATCH.
CL-USER 81 > (mismatch '(a b c e f) '(a b d e f))
2
CL-USER 82 > (mismatch '(a b c e f) '(a b d e f) :from-end t)
3
CL-USER 83 > (defun identical-head (s1 s2)
(let ((m (mismatch s1 s2)))
(if (numberp m)
(subseq s1 0 m)
s1)))
IDENTICAL-HEAD
CL-USER 84 > (identical-head '(a b c e f) '(a b d e f))
(A B)
CL-USER 85 > (defun identical-tail (s1 s2)
(let ((m (mismatch s1 s2)))
(if (numberp m)
(subseq s1 (1+ m))
s1)))
IDENTICAL-TAIL
CL-USER 86 > (identical-tail '(a b c e f) '(a b d e f))
(E F)
The third function is more complicated:
CL-USER 87 > (defun identical-tail-head (s1 s2 &aux (l1 (length s1)))
(loop for i from 0 below l1
for m = (mismatch s2 s1 :start2 i)
when (and m (= (+ i m) l1))
do (return (subseq s1 i))))
CL-USER 88 > (identical-tail-head '(a e d b c d) '(b c d a f))
(B C D)
Upvotes: 3
Reputation: 223023
No, there are no standard operators for these. But identical-head
is not hard to write:
(defun identical-head (l1 l2)
(and l1 l2 (equal (car l1) (car l2))
(cons (car l1) (identical-head (cdr l1) (cdr l2)))))
I don't know of an easier way to write identical-tail
except reversing the input lists, calling identical-head
, and then reversing the result, since lists only allow forward traversal, not backward.
(defun identical-tail (l1 l2)
(reverse (identical-head (reverse l1) (reverse l2))))
Here's how I'd write identical-tail-head
:
(defun identical-tail-head (l1 l2)
(labels ((starts-with-p (list prefix)
(cond ((null prefix) t)
((null list) nil)
((equal (car list) (car prefix))
(starts-with-p (cdr list) (cdr prefix))))))
(cond ((null l1) nil)
((starts-with-p l2 l1) l1)
(t (identical-tail-head (cdr l1) l2)))))
It's not a very efficient way to do it, since it's O(n²), but (again) given that lists are forward-traversal-only, I haven't come up with a better way.
Upvotes: 1