By Erick Engelke
September 13, 2025
ECMAScript (also known as JavaScript) added significant set functionality in recent years.
For our purposes, a set is like a list of strings. It could be a list of courses, or a list of people names, etc., anything you might want to compare.
With the following unit, you can declare sets with simple logic of unions, differences, etc.
procedure TForm1.Form1Show(Sender: TObject);
var
A, B, C : TNiceSet;
begin
A := newSet(['a','b','c']);
B := newSet(['b','c','d']);
multilineedit1.Lines.Add('A = ' + dumpstringArray( SetToArray( A )));
multilineedit1.Lines.Add('B = ' + dumpstringArray( SetToArray( B )));
C := A.union(B);
multilineedit1.Lines.Add('A.Union(B) = '+ dumpStringArray( SetToArray(c)) );
C := A.difference( B );
multilineedit1.Lines.Add('A.Difference(B) = '+ dumpStringArray( SetToArray(c)) );
C := A.symmetricDifference( B );
multilineedit1.Lines.Add('A.SymmetricDifference(B) = '+ dumpStringArray( SetToArray(c)) );
C := A.intersection( B );
multilineedit1.Lines.Add('A.Intersection(B) = '+ dumpStringArray( SetToArray(c)) );
end;
which produces the following output.
A = a, b, c
B = b, c, d
A.Union(B) = a, b, c, d
A.Difference(B) = a
A.SymmetricDifference(B) = a, d
A.Intersection(B) = b, c
Note
|
this will not work with Internet Explorer or the EWB IDE, but it works with all modern browsers of the last year. |
Here’s the full source code.
It makes reference to nicesetutils.wbs which is included in my Nice toolkit, but I’m sharing this file here too.
unit nicesetutils;
interface
uses WebCore, webdom;
type
TStringArray = array of string;
external TNiceSet = class( TExternalObject )
public
procedure clear;
procedure add( s : string );
procedure delete( s : string );
function entries: variant;
function union( secondset : TNiceSet ):TNiceSet;
function intersection( secondset : TNiceSet ) : TNiceSet;
function difference( secondset : TNiceSet ) : TNiceSet;
function symmetricDifference( secondset : TNiceSet ): TNiceSet;
function isSubsetOf( secondset : TNiceSet ) : boolean;
function isSuperSetOf( secondset : TNiceSet ):boolean;
function isDisjointFrom( secondset : TNiceSet ): boolean;
function toString : string;
property size : integer read;
function values: variant;
end;
// some functions
function newSet( arr : array of string ) : TNiceSet;
function SetToArray( setvar : TNiceSet ) : TStringArray;
function dumpStringArray( arr : TStringArray ) : string;
implementation
var
external internal_set_arr : array of string;
external internal_set : TNiceSet;
external function SetToArrayInternal( arr : variant ):TStringArray;
function newSet( arr : array of string ) : TNiceSet;
begin
internal_set_arr := arr;
result := TNiceSet(CreateObject('new Set( internal_set_arr )'));
end;
function SetToArray( setvar : TNiceSet ) : TStringArray;
begin
internal_set_arr := [];
CreateObject(' SetToArrayInternal= function( arr ) { i = 0; for (const entry of arr ) internal_set_arr[i++] = entry;}');
SetToArrayInternal( setvar.values );
result := internal_set_arr;
end;
function dumpStringArray( arr : TStringArray ) : string;
var
i : integer;
begin
result := '';
for i := 0 to length( arr ) - 1 do begin
if i > 0 then result := result +', ';
result := result + arr[i];
end;
end;
end.
The only function which is really complicated is SetToArray() which is creates an internal JavaScript function because we need to implement
for ( const entry of arr ) ....
and EWB doesn’t support that iterator-type for loop. So we dynamically create the function and call it.