listdiff.sci

The function listdiff returns the differences of two vectors in the style of the diff(1) command. It is a funny example of doing something completely non-numerical with Scilab.

function diff = listdiff(lst1, lst2, equ)
// implement a diff(1) like function for vectors.
// The caller can supply a bool equ(x, y) function
// that will be used in all comparisions, otherwise
// operator "==" is used.
//
// RETURN VALUE
// 2-column vector describing the differences.
// Column 1 contains the element and column 2
// the element's index.  A "+" in front of the
// index means: "Extra element in lst2", a "-"
// means missing element in lst1.

[nl, nr] = argn(0);
select nr
case 0 then
    error("Too few arguments.  Got 0, require 2 or 3.");
case 1 then
    error("Too few arguments.  Got 1, require 2 or 3.");
case 2 then
    deff('b = equ(s1, s2)', 'b = s1 == s2');
case 3 then
    // caller supplied equ()
    if type(equ) ~= 13 then
        error("Function expected, got a " + typeof(equ) + ".");
    end
else
    error("Too many arguments.  Got " + string(nr) + " require 2 or 3.");
end

if type(lst1) ~= 1 & type(lst2) ~= 1 then
    // none of the lists is empty
    if type(lst1) ~= type(lst2) then
        error("Both lists must be of the same type, or be empty.");
    end
end

fuzz = 10;

diff = [];
n1 = size(lst1, 1);
n2 = size(lst2, 1);


// special cases

if n1 == 0 & n2 == 0, return, end

if n1 == 0 then
    p = 1 : n2;
    diff = [lst2, "+" + string(p')];
    return;
end

if n2 == 0 then
    p = 1 : n1;
    diff = [lst1, string(-p')];
    return;
end


// general case (neither list is empty)

i = 1;
j = 1;
while i <= n1 & j <= n2
    while i <= n1 & j <= n2
        if ~equ(lst1(i), lst2(j)), break, end
        i = i + 1;
        j = j + 1;
    end
    if i >= n1 | j >= n2, break, end

    icurs = i;
    while icurs <= min(n1, i+fuzz) 
        if equ(lst1(icurs), lst2(j)), break, end
        icurs = icurs + 1;
    end
    if icurs <= n1 then
        if equ(lst1(icurs), lst2(j)) then
            // record element(s) missing from lst1
            for p = i : icurs-1
                this_diff = [lst1(p), string(-p)];
                diff = [diff; this_diff];
            end
            // re-sync
            i = icurs;
        end
    end

    jcurs = j;
    while jcurs <= min(n2, j+fuzz) 
        if equ(lst1(i), lst2(jcurs)), break, end
        jcurs = jcurs + 1;
    end
    if jcurs <= n2 then
        if equ(lst1(i), lst2(jcurs)) then
            // record extra element(s) in lst2
            for p = j : jcurs-1
                this_diff = [lst2(p), "+" + string(p)];
                diff = [diff; this_diff];
            end
            // re-sync
            j = jcurs;
        end
    end
end