-1

Does any existing programming language, particularly in the Lisp or ML families, have a library function to calculate list difference in the sense of 'first until start of second' - I'm not sure offhand what it should be called exactly - for example, considering strings as lists of characters, if the inputs are:

abcdef
def

Then the output would be

abc
chris
  • 4,988
  • 20
  • 36
rwallace
  • 31,405
  • 40
  • 123
  • 242

3 Answers3

3

Code in Common Lisp:

CL-USER 1 > (defun fusos (s1 s2)
              (let ((pos (search s2 s1)))
                (when pos (subseq s1 0 pos))))
FUSOS

CL-USER 2 > (fusos '(a b c d e f) '(d e f))
(A B C)
Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
  • Right, that's a good way to implement it - I guess there isn't any standard name for it? What about `take-upto`? – rwallace May 08 '13 at 04:35
  • There is a standard name for this kind of function - `take-while` (which takes a predicate). It may have different name in different FP languages – Ankur May 08 '13 at 05:18
3

There's already an accepted answer, but Common Lisp's LDIFF (short for "list difference") is still worth mentioning. It is based on the structure of lists (the cons cells the list is made of) rather than the elements of the list, so the list being "subtracted" has to be the same cons cell as some tail of the list. It's a bit more specific, but it certainly computes a list difference.

CL-USER> (let* ((abcdef '(a b c d e f))
                (def (cdddr abcdef)))
           (ldiff abcdef def))
(A B C)
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
  • You probably want to quote the symbols a, b, c, d, e, f. Also to make it clear: the cons cells need to be the same. Same means 'identical'. – Rainer Joswig May 08 '13 at 17:01
  • @RainerJoswig Yeah, those should be quoted. I'd started with `'(a b c d e f)`, and then edited when SO's syntax highlighting didn't like the "unmatched single quote". As to the cons cells, that's mentioned in the answer: "based on the structure of the lists (i.e., the cons cells the list is made of)", but I can make that clearer. – Joshua Taylor May 08 '13 at 17:36
1

Since takeWhile was mentioned in a comment and Haskell has this function, here is how you could achieve the desired result in Haskell:

takeWhile (flip notElem ys) xs

where your example would be

takeWhile (flip notElem "def") "abcdef"

That is, you take elements from the list xs as long as they are not contained in the list ys. As soon as you find an element that is contained in ys (or hit the end of xs) you stop.

In Standard ML it would be:

fun take_while p [] = []
  | take_while p (x::xs) =
    if p x then x :: take_while p xs
    else []

EDIT: Above, I assumed that the specification was that we stop in the first list, as soon as we find an (arbitrary) element of the second list. Hence the use of takeWhile. However, from the OP it is not clear to me what the actual specification is. If it is remove an existing suffix (the second list) from the input (the first list), then the solution is of course different. In Haskell, without thinking about efficiency, we could do:

removeSuffix [] ys = []
removeSuffix xs@(z:zs) ys
  | xs == ys = []
  | otherwise = z : removeSuffix zs ys
chris
  • 4,988
  • 20
  • 36
  • I may be reading this wrong, but this doesn't look like it takes "first until start of second [where second is a suffix of first]." Wouldn't this implementation have `takeWhile (flip notElem "def") "abcdefghdef"` return `"abc"` rather than `"abcdefgh"`, since it would stop after `"abc"` because `d` is an element of `"def"`? – Joshua Taylor May 09 '13 at 11:01
  • @JoshuaTaylor Yes, I thought that was the desired behavior. Though after reading the OP again, I agree that I am probably wrong about that. – chris May 09 '13 at 11:11