264 строки
4.8 KiB
Plaintext
264 строки
4.8 KiB
Plaintext
% Functions that operate on sets in the form of arrays and lists:
|
|
% Copyright (C) 2010-2017,2018 John E. Davis
|
|
%
|
|
% This file is part of the S-Lang Library and may be distributed under the
|
|
% terms of the GNU General Public License. See the file COPYING for
|
|
% more information.
|
|
%
|
|
% Functions: unique, union, complement, intersection, ismember
|
|
private define pop_set_object ()
|
|
{
|
|
variable a = ();
|
|
if ((typeof(a) != Array_Type) && (typeof(a) != List_Type))
|
|
a = [a];
|
|
return a;
|
|
}
|
|
|
|
private define list_unique (a)
|
|
{
|
|
variable len = length(a);
|
|
variable indices = Int_Type[len];
|
|
variable i, j, k;
|
|
|
|
k = 0;
|
|
_for i (0, len-1, 1)
|
|
{
|
|
variable a_i = a[i];
|
|
_for j (0, i-1, 1)
|
|
{
|
|
if (_eqs(a_i, a[j]))
|
|
break;
|
|
}
|
|
then
|
|
{
|
|
indices[k] = i;
|
|
k++;
|
|
}
|
|
}
|
|
return indices[[0:k-1]];
|
|
}
|
|
|
|
|
|
define unique ()
|
|
{
|
|
variable i, j, len;
|
|
variable a;
|
|
|
|
if (_NARGS != 1)
|
|
{
|
|
_pop_n (_NARGS);
|
|
usage ("i = unique (a); %% i = indices of unique elements of a");
|
|
}
|
|
|
|
a = pop_set_object ();
|
|
if (typeof(a) == List_Type)
|
|
{
|
|
try
|
|
{
|
|
a = list_to_array (a);
|
|
}
|
|
catch AnyError: return list_unique (a);
|
|
}
|
|
|
|
len = length(a);
|
|
if (len <= 1)
|
|
return [0:len-1];
|
|
|
|
if (length(array_shape(a)) != 1)
|
|
a = _reshape (__tmp(a),[len]);
|
|
|
|
try
|
|
{
|
|
i = array_sort(a);
|
|
}
|
|
catch AnyError: return list_unique (a);
|
|
|
|
a = a[i];
|
|
if (a[0] == a[-1]) % all equal
|
|
return [0];
|
|
j = where (shift(a,-1)!=a);
|
|
% Now, i contains the sorted indices, and j contains the indices into the
|
|
% sorted array. So, the unique elements are given by a[i][j] where a is
|
|
% the original input array. It seems amusing that the indices given by
|
|
% [i][j] are also given by i[j].
|
|
return i[__tmp(j)];
|
|
}
|
|
|
|
define union ()
|
|
{
|
|
!if (_NARGS)
|
|
usage ("U = union (A, B, ..., C);");
|
|
|
|
variable args = {}, obj;
|
|
variable has_list = 0;
|
|
loop (_NARGS)
|
|
{
|
|
has_list += (typeof (obj) == List_Type);
|
|
obj = pop_set_object ();
|
|
list_insert (args, obj);
|
|
}
|
|
|
|
variable a = NULL;
|
|
if (has_list == 0)
|
|
{
|
|
try
|
|
{
|
|
a = [__push_list (args)];
|
|
}
|
|
catch AnyError:;
|
|
}
|
|
|
|
if (a == NULL)
|
|
{
|
|
a = {};
|
|
foreach obj (args)
|
|
{
|
|
if (typeof(obj) == List_Type)
|
|
{
|
|
list_join (a, obj);
|
|
continue;
|
|
}
|
|
foreach (obj)
|
|
{
|
|
variable x = ();
|
|
list_append (a, x);
|
|
}
|
|
}
|
|
}
|
|
return a[unique (a)];
|
|
}
|
|
|
|
% return indices of a that are not in b
|
|
private define list_complement (a, b)
|
|
{
|
|
variable lena = length(a), lenb = length(b);
|
|
variable indices = Int_Type[lena];
|
|
variable i, j, k;
|
|
|
|
k = 0;
|
|
_for i (0, lena-1, 1)
|
|
{
|
|
variable a_i = a[i];
|
|
_for j (0, lenb-1, 1)
|
|
{
|
|
if (_eqs(a_i, b[j]))
|
|
break;
|
|
}
|
|
then
|
|
{
|
|
indices[k] = i;
|
|
k++;
|
|
}
|
|
}
|
|
return indices[[0:k-1]];
|
|
}
|
|
|
|
define complement ()
|
|
{
|
|
variable a, b;
|
|
if (_NARGS != 2)
|
|
usage ("\
|
|
i = complement (a, b);\n\
|
|
%% Returns the indices of the elements of `a' that are not in `b'");
|
|
|
|
b = pop_set_object ();
|
|
a = pop_set_object ();
|
|
|
|
variable
|
|
lena = length(a),
|
|
lenb = length(b);
|
|
|
|
if ((lena == 0) || (lenb == 0))
|
|
return [0:lena-1];
|
|
|
|
variable sia, sib;
|
|
try
|
|
{
|
|
if (typeof (a) == List_Type)
|
|
a = list_to_array (a);
|
|
if (typeof (b) == List_Type)
|
|
b = list_to_array (b);
|
|
sia = array_sort (a);
|
|
sib = array_sort (b);
|
|
}
|
|
catch AnyError:
|
|
return list_complement (a, b);
|
|
|
|
variable
|
|
c = Int_Type [lena], j = 0,
|
|
ia, ib, xa, xb, k;
|
|
|
|
ia = 0; ib = 0;
|
|
xb = b[sib[ib]];
|
|
while (ia < lena)
|
|
{
|
|
k = sia[ia];
|
|
xa = a[k];
|
|
if (xa < xb)
|
|
{
|
|
c[j] = k;
|
|
j++;
|
|
ia++;
|
|
continue;
|
|
}
|
|
if (xb == xa)
|
|
{
|
|
ia++;
|
|
continue;
|
|
}
|
|
|
|
while (ib++, (ib < lenb) && (xa > b[sib[ib]]))
|
|
;
|
|
if (ib == lenb)
|
|
{
|
|
variable n = lena-ia;
|
|
c[[j:j+n-1]] = sia[[ia:lena-1]];
|
|
j += n;
|
|
break;
|
|
}
|
|
xb = b[sib[ib]];
|
|
if (xa == xb)
|
|
ia++;
|
|
}
|
|
return c[[0:j-1]];
|
|
}
|
|
|
|
% Return the indices into a of the common elements of both a and b
|
|
define intersection ()
|
|
{
|
|
if (_NARGS < 2)
|
|
usage ("\
|
|
i = intersection (a, b, .., c);\n\
|
|
%% Returns the indices of 'a' of the common elements of b,.., c");
|
|
|
|
variable b = pop_set_object ();
|
|
loop (_NARGS-1)
|
|
{
|
|
variable a = pop_set_object ();
|
|
variable i = complement (a, __tmp(b));
|
|
i = complement (a, a[i]);
|
|
b = a[i];
|
|
}
|
|
return i;
|
|
}
|
|
|
|
% Returns whether or not a is a member of b.
|
|
define ismember ()
|
|
{
|
|
if (_NARGS != 2)
|
|
usage ("I = ismember (a, b);\n\
|
|
Returns a boolean array indicated whether the corresponding elements of 'a'\n\
|
|
are members of 'b'");
|
|
|
|
variable a, b;
|
|
(a, b) = ();
|
|
if ((typeof(a) == Array_Type) || (typeof(a) == List_Type))
|
|
{
|
|
variable lena = length (a);
|
|
variable result = Char_Type[lena];
|
|
result[intersection(a,b)] = 1;
|
|
return result;
|
|
}
|
|
return 0 != length (intersection (a, b));
|
|
}
|