Jump to content
Sign in to follow this  
Attila Kovacs

Generic set comparer

Recommended Posts

Is there a mature library for generic (multi)set operations?

 

(Edit: Reading my topic, i meant mathematical sets, maybe I could name it List instead of set, the result what counts)

 

I'd imagine that working like this:

 

unit xyz.sets;

interface

uses
  System.Generics.Defaults;

type
  TSets<T> = class
  public type
    TSet = class
    private
      FValues: TArray<T>;
    public
      procedure Add(AValue: T);
    end;
  private
  var
    FSets: TArray<TSet>;
    FComparer: IEqualityComparer<T>;
  public
    constructor Create;
    function AddSet: TSet;
    function GetIntersection(ASets: array of TSet): TArray<T>;
    property Comparer: IEqualityComparer<T> read FComparer write FComparer;
  end;

implementation

uses
  System.SysUtils;

{ TSets<T> }

function TSets<T>.AddSet: TSet;
var
  l: integer;
begin
  Result := TSet.Create;
  l := Length(FSets);
  SetLength(FSets, l + 1);
  FSets[l] := Result;
end;

{ TSets<T>.TSet }

procedure TSets<T>.TSet.Add(AValue: T);
var
  l: integer;
begin
  l := Length(FValues);
  SetLength(FValues, l + 1);
  FValues[l] := AValue;
end;


constructor TSets<T>.Create;
begin
  FComparer := TEqualityComparer<T>.Default;
end;

// O(n^x)
function TSets<T>.GetIntersection(ASets: array of TSet): TArray<T>;
var
  i, j, k, l: integer;
begin
  if FComparer = nil then
    raise Exception.Create('No comparer defined.');
  if Length(ASets) > 1 then
  begin
    for i := 0 to High(ASets[0].FValues) do
      for j := 1 to High(ASets) do
        for k := 0 to High(ASets[j].FValues) do
          if FComparer.Equals(ASets[0].FValues[i], ASets[j].FValues[k]) then
          begin
            l := Length(Result);
            SetLength(Result, l + 1);
            Result[l] := ASets[0].FValues[i];
          end;
  end
  else
    Result := ASets[0].FValues;
end;

end.

------  ------  ------  ------  ------  ------  ------  ------  ------

program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  xyz.sets in 'xyz.sets.pas';

var
  rp: procedure;

  i: integer;
  sets: TSets<string>;
  set1, set2: TSets<string>.TSet;
  res: TArray<string>;


procedure x;
begin
  ExitProcessProc := rp;
  ReadLn;
end;


begin
  ReportMemoryLeaksOnShutdown := True;
  rp := ExitProcessProc;
  ExitProcessProc := x;

  sets := TSets<string>.Create;
  set1 := sets.AddSet;
  set2 := sets.AddSet;
  try
    set1.Add('hello');
    set1.Add('leo');

    set2.Add('hello');
    set2.Add('bello');

    res := sets.GetIntersection([set1, set2]);
    for i := 0 to High(res) do
      WriteLn(res[i]);

  finally
    set1.Free;
    set2.Free;
    sets.Free;
  end;

end.

 

Edited by Attila Kovacs

Share this post


Link to post

Not aware of any library, but I have written small routines like

  function AnyOf(ATarget, AActual: TOptionSet): Boolean;  and

  function Contains(ATarget, AActual: TOptionSet): Boolean;  

 

Makes the code more readable, I think, which is all I really needed. My notion was that although the set operations are pretty terse, not a lot of devs spend much time reading them, so comprehension may be a struggle. AnyOf() handles any members of the target being present in the actual:

    Result := ATarget * AActual <> [];

while Contains() tests:

    Result := ATarget * AActual = ATarget;

 

Unless your need is for a lot of densely coded operations, this kind of thing may be sufficient. If you do need dense code, then you may better simply use the existing operators.

Share this post


Link to post

Ahm, i was afraid that using the word "set" would be misleading, and I was right, sorry, but lists are a bit different from multisets again, so I don't know,

I need to compare two or more "set of anything" and I'm tired writing it always manually.

 

Share this post


Link to post
24 minutes ago, Attila Kovacs said:

Ahm, i was afraid that using the word "set" would be misleading, and I was right, sorry, but lists are a bit different from multisets again, so I don't know,

I need to compare two or more "set of anything" and I'm tired writing it always manually.

 

Ah, I did indeed misunderstand. So really, you want set operations on collections of whatever type. 

Share this post


Link to post
2 hours ago, Attila Kovacs said:

@Leif Uneus Wow, thanks a lot, and also to LU RD if he ever reads this.

Well. there is no secret that LU RD is short for Leif Uneus R&D Manager of Opsis AB, a company that provides analysers and software for industrial and environmental analysis of gases and particulates.

A company started 36 years ago by me and my business partner.

 

Core software in the analysers is built with Turbo Pascal 7. Delphi is a tool for our software for data management, analysis and reporting.

Edited by Leif Uneus
  • Like 1

Share this post


Link to post

Can we please sit for a while and appreciate how cute the separating line with scissors is

  • Haha 2

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×