On Jun 2, 2009, at 11:22 PM, Wilson MacGyver wrote:

>
> More newbie questions. :)
>
> If I have two sequences as follow:
>
> (2 3 4 5 6 7 8 9 10)
> (4 6 8 10)
>
> what's the best way to subtract the 2nd sequence from the first one?
>
> The best I can come up with was to do (first) on 2nd sequence  and  
> turn around
> and do a (remove) on the first sequence, etc until I exhaust the 2nd  
> sequence.

In Clojure, the set data structure is awesome. I have nothing to add  
to that. However, I had to do this the other day in Javascript (which  
lacks a decent set type) and the algorithm I came up with is this:

sort both sequences
walk down both sequences:
   if the remove list item is greater than the list item, add it to  
the result and increment the remove list index
   if the remove list item is less than the list item, increment the  
list index
   if they are equal, increment the remove list index

I believe this algorithm to be O(n log n) because the subtraction  
operation should take O(MAX(n,m)) and that ought to be dominated by  
the O(n log n) for sorting whichever input list is bigger. The naive  
method ought to be O(n*m) because for each element of one list you  
have to do a complete traversal of the other list. If the lists are  
comparable in size it would start to resemble O(n^2).

Pretty off-topic, I know, but the function I came up with is this:

// returns the subtraction of two sorted lists
function subtract(a1, a2) {
        var i = 0, j = 0, result = [];
        
        // walk down both lists
        while (i < a1.length && j < a2.length) {
                
                // the list item is less than the remove item
                if (a1[i] < a2[j]) {
                        // stick it on the result and move along the list
                        result.push(a1[i]);
                        i++;
                }
                else if (a1[i] > a2[j])
                        // the list item exceeds the remove item, so we need to 
move along  
the
                        // remove items
                        j++;
                else
                        // the items are equal, so continue testing the list 
with this item  
of
                        // the remove list
                        i++;
        }

        // glob on the remainder of the list
        if (i < a1.length)
                result = result.concat(a1.splice(i));
                
        return result;
}

I'm sure Clojure's sets do this kind of thing more efficiently but if  
you have to do it in a language without a decent set data structure  
you can fall back on that algorithm. Of course, I don't think you'll  
notice an improvement over the naive method until you hit several  
thousand elements or have similarly sized input lists.

—
Daniel Lyons
http://www.storytotell.org -- Tell It!


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to