Jump to content
dummzeuch

set of object instances

Recommended Posts

I would like to have a set of some objects of the same class e.g. TEdit.

 

Of course TEdit is not an ordinal type, so set of TEdit won't work.

 

Is there some (generics?) container type that lets me

  • Add Object instances to it, ignoring duplicates
  • Check if an object instance is in the list
  • Or even better lets me enumerate over all the object instances in the list

 

So I can do something link this:

var
  EditSet = TSet<TEdit>;
  ed: TEdit;
 begin
   EditSet.Add(Edit1);
   EditSet.Add(Edit1)
   EditSet.Add(Edit2);
   EditSet.Add(Edit4);
   
   if EditSet.Contains(Edit1) then
     Edit1.Text := 'Was in set');
     
   if EditSet.Contains(Edit3) then
     Edit3.Text := 'Was in set');
   
   // or even better:
   for ed in EditSet do
     ed.Text := 'Was in set';
end;

I'd prefer using something ready made from the RTL, if it exists.

Edited by dummzeuch
Add Edit1 twice

Share this post


Link to post

Spring has a collection that meets your needs. With pure rtl you can fake it with a geneic dictionary. 

Edited by David Heffernan

Share this post


Link to post

TDictionary<TObject, Boolean>

Your objects are the keys, and the value can essentially be ignored. Use AddOrSetValue, and KeyExists.

 

Might go the next step and just create some kind of hash table if I were doing this a lot. I doubt the overhead of having an un-needed value is worth it though.

Edited by Brandon Staggs
  • Like 2

Share this post


Link to post
11 minutes ago, Lajos Juhász said:

You could also use a generic list? That also has everything you wrote above.

What happens, when I add the same object twice? In a set, the duplicate will be discarded, but in a list?

Edited by dummzeuch

Share this post


Link to post
22 minutes ago, dummzeuch said:

What happens, when I add the same object twice? In a set, the duplicate will be discarded, but in a list?

The list would contain the control twice (like a multiset).

 

If you don't want an object twice you can before add check indexof.

Share this post


Link to post
2 hours ago, Lajos Juhász said:

You could also use a generic list? That also has everything you wrote above.

 

 

Doesn't handle duplicates

Share this post


Link to post
4 minutes ago, David Heffernan said:

Doesn't handle duplicates

the original post doesn't said if it's a multiset or not.

Share this post


Link to post
1 minute ago, Lajos Juhász said:

the original post doesn't said if it's a multiset or not.

Yes they did

3 hours ago, dummzeuch said:

Add Object instances to it, ignoring duplicates

 

Share this post


Link to post

All these people suggesting TList (i.e. an array) are just asking for performance problems if ever the collection has a significant size.

  • Like 1

Share this post


Link to post
24 minutes ago, David Heffernan said:

if ever the collection has a significant size

With a list of TEdits? Not likely.

 

I would go for an encapsulated TList<T>:

type
  TSetOfStuff<T> = class
  private
    FList: TList<T>;
  public
    function Contains(const Value: T): boolean;
    function Add(const Value: T): integer;
    procedure Remove(const Value: T);
    function GetEnumarator: TEnumerator<T>;
  end;

function TSetOfStuff<T>.Contains(const Value: T): boolean;
begin
  var Index: integer;
  Result := FList.BinarySearch(Value, Index);
end;

function TSetOfStuff<T>.Add(const Value: T): integer;
begin
  if (not FList.BinarySearch(Value, Result)) then
    FList.Insert(Result, Value);
end;

procedure TSetOfStuff<T>.Remove(const Value: T);
begin
  var Index: integer;
  if (FList.BinarySearch(Value, Index)) then
    FList.Delete(Index);
end;

function TSetOfStuff<T>.GetEnumarator: TEnumerator<T>;
begin
  Result := FList.GetEnumerator;
end;

etc...

 

  • Thanks 1

Share this post


Link to post

This was about a set with at most 20 different entries, so performance would most likely not have been an issue (when I asked the question, it was only 5).

 

I have solved the actual problem differently by now. A set is still involved, but not a set of object instances but simply a classical set of an enum.

Share this post


Link to post

I'm unclear why you keep thinking of it like a Set. In my mind, it's just a collection (bag) of objects and you want to know if a given object is in it or not. If so, you get back True. If not, you get back False. If the semantics are that you don't want dups, then you only add to the bag after you get back False from a test for inclusion.

 

In the DB world, I've seen lots of times when someone creates a method like, "AddOrUpdateWidget( aWidget : TWidget )" that subsumes the test to see if the widget is already there or not.

Share this post


Link to post
9 hours ago, David Schwartz said:

I'm unclear why you keep thinking of it like a Set. In my mind, it's just a collection (bag) of objects and you want to know if a given object is in it or not. If so, you get back True. If not, you get back False. If the semantics are that you don't want dups, then you only add to the bag after you get back False from a test for inclusion.

What you've described is a set. So that's why he keeps thinking of it as a set. 

  • Like 1

Share this post


Link to post
14 hours ago, David Heffernan said:

What you've described is a set. So that's why he keeps thinking of it as a set. 

A "set" in Pascal is a collection of the same types of things where their value reflects a position in the set, meaning they can be expressed as ordinal values between 0 and the upper limit of members the compiler allows.

 

If you want to use objects then their ordinal values can easily correspond to their memory location cast as an integer, which would be a 32- or 64-bit value, and the set itself would take up far more than available memory.

 

 Alternatively, the values could be hashed to result in a smaller container.

 

But there's also this data structure called a "bag" which is an unordered collection of related things where you're only interested in whether something is "in the bag" or not. That's how databases tend to be organized, and indices are used to make tests for inclusion go much faster.

 

In Pascal, a "set" is tightly correlated with its implementation, where members have ordinal values corresponding to unique bits in the allocated space. The compiler manages those values, in contrast to the values of object locations in memory, which are highly random.

 

Look, I didn't invent any of this. I rarely use "sets" in Pascal because of this inherent limitation. I work mostly with objects, and you cannot put an object into a Pascal "set" nor test for its presence.

 

But from a theoretical viewpoint, EVERYTHING is a "set" in my mind, which really doesn't resolve anything from a programming standpoint.

Share this post


Link to post
7 minutes ago, David Schwartz said:

A "set" in Pascal 

I'm not talking about a Pascal or Delphi set. I'm talking about a set in general, non language or implementation terms. And that's that the question was about. 

 

Also there are a number of libraries that define set collections that aren't native Delphi set types. I'm thinking spring4d for example.

Share this post


Link to post
Quote

In computer science, a set is an abstract data type that can store unique values, without any particular order. It is a computer implementation of the mathematical concept of a finite set. Unlike most other collection types, rather than retrieving a specific element from a set, one typically tests a value for membership in a set.

https://en.wikipedia.org/wiki/Set_(abstract_data_type)

  • Like 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

×