Uncouple
June 15, 2018
Today’s exercise is from a programming textbook:
A couple is two adjacent identical items in a sequence. You are to remove all couples, then process the list recursively to remove any additional couples formed by the removal of the original couples. For instance, given the list {red blue green green blue red yellow}, first remove the green couple, leaving {red blue blue red yellow}, then remove the blue couple, leaving {red red yellow}, and finally remove the red couple, leaving {yellow}.
Your task is to write a program to uncouple a list. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
Here is a standard Scheme solution using fold from SRFI 1.
If you don’t need the intermediate results, it’s straightforward to do all the matches and deletions in a single pass:
(define (uncouple ls)
(let loop ((past ‘())
(future ls))
(cond ((null? future) (reverse past))
((and (pair? past) (eq? (car past) (car future)))
(loop (cdr past) (cdr future)))
(else
(loop (cons (car future) past) (cdr future))))))
Mumps version
Here’s a solution in C.
Example:
Works nicely with Haskel pattern matching:
A solution in Racket.
@matthew: Can you explain what the Haskell example is doing?
A solution in c#
void Main()
{
var input = new[] {1,2,2,1,3,3,3,4,4,3,5,4,4,5,5,5,5,5};
input.Uncouple().Dump();
input.Uncouple().Uncouple().Dump();
}
public static class UncoupleExtensions
{
public static IEnumerable Uncouple(this IEnumerable input)
{
return Uncouple(input, Comparer.Default);
}
}
In Ruby.
Output:
yellow
@V, in the example you gave I believe that only two of the “green” elements should be removed, as opposed to all three.
Here’s a Ruby implementation that retains one of the “green” elements.
Output:
Clojure/Script
Test:
cljs.user=> (remove-dups '(red blue green green blue red yellow))
(yellow)
Common Lisp, (complicated) destructive function that does not require to reverse the intermediate result.
Test:
* (nuncouple '(red blue green green blue red yellow))
(YELLOW)
@matthew: I get this when following your solution in GHCi
Prelude> uncouple s = reverse(aux s []) where
Prelude> aux [] t = t
Prelude> aux (a:s) (b:t) | a == b = aux s t
Prelude> aux (a:s) t = aux s (a:t)
Prelude> print(uncouple[1,2,3,3,4,4,2])
*** Exception: :22:3-27: Non-exhaustive patterns in function aux
Prelude>
@Steve: Don’t know what’s going on there with the ghci repl – I run the program with “runghc uncouple.hs” which seems to do the right thing. For your question above (I’d have replied sooner, but I’ve been on holiday) – the idea is much the same as many of the other solutions, maintain a stack of processed items, when the next item in input and the stack top are the same, discard both, otherwise copy the next input to the stack – the main work is done by the second clause in aux, which combines pattern matching and a boolean guard.
@matthew: Thanks, tried it your way and it worked fine. Then tried the following with a new uncouple.hs:
uncouple s = reverse(aux s []) where
aux [] t = t
aux (a:s) (b:t)
| a == b = aux s t
aux (a:s) t = aux s (a:t)
main = print(uncouple[“red”,”red”,”blue”,”green”,”green”,”blue”,”red”,”yellow”,”yellow”])
GHCi, version 8.4.3: http://www.haskell.org/ghc/ :? for help
Prelude> :l c:\Users\Steve\Documents\uncouple.hs
[1 of 1] Compiling Main ( C:\Users\Steve\Documents\uncouple.hs, interpreted )
Ok, one module loaded.
*Main> main
[“red”]
*Main>