Recent

Author Topic: [Solved] How do I determine the number of elements in a variable of a set type?  (Read 498 times)

Yukiko

  • New member
  • *
  • Posts: 27
Here's the gist of my problem: I need to know how many elements (Is that the right word?) are in a variable I am receiving, whose type is a set of days of the week, similar to the way Length() is for arrays. All I actually need to know is if the variable is empty but it might be useful to know the size as well.

Unfortunately, I was unable to find anything in the documentation that pertained to this.
« Last Edit: December 04, 2018, 10:10:58 am by Yukiko »

Yukiko

  • New member
  • *
  • Posts: 27
Re: How do I determine the number of elements in a variable of a set type?
« Reply #1 on: December 04, 2018, 10:10:07 am »
I solved my problem with a simple for loop.

This is the snippet of my solution I extracted from my code. Warning this is only a snippet. :)
Code: Pascal  [Select]
  1. Type
  2.   DaysOfTheWeek = (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday);
  3.   SchedDays = Set of DaysOfTheWeek;
  4.  
  5. Var
  6.   Schedule : SchedDays; // Contains some DaysOfTheWeek elements.
  7.   I: DaysOfTheWeek;
  8.   Count: Integer;
  9.  
  10. begin
  11.   Count := 0;
  12.   For I := Sunday to Saturday Do If(I in Schedule) Then Count := Count +1;
  13.   Writeln(Count);
  14. End;
  15.  

This will print the number of "things" in Schedule.

I am still interested if there is a function to do the same thing but if not this serves the purpose.
Thanks again to the community for the help you folks have been to me.

GetMem

  • Hero Member
  • *****
  • Posts: 3255
Code: Pascal  [Select]
  1. type
  2.   DaysOfTheWeek = (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday);
  3.   SchedDays = Set of DaysOfTheWeek;
  4.  
  5. var
  6.   Schedule : SchedDays;
  7. begin
  8.   Schedule := [Sunday, Monday, Thursday];
  9.   Writeln(PopCnt(DWord(Schedule)));
  10. end.

Ps: Always use the Low and High function when you looping through an array or set. You cannot go wrong with that.

wp

  • Hero Member
  • *****
  • Posts: 5129
All I actually need to know is if the variable is empty...
Code: Pascal  [Select]
  1. if Schedule = [] then ...
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

howardpc

  • Hero Member
  • *****
  • Posts: 2833
Note that GetMem's use of PopCnt on a typecast set is implementation dependent, and works only for small sets (and here, of course, the set size cannot exceed 7).
Here's a fuller example.
Code: [Select]
program Project1;

{$Mode objfpc}{$H+}
{$ModeSwitch advancedrecords}

type
  TDay = (dSun, dMon, dTue, dWed, dThu, dFri, dSat);
  TDays = set of TDay;

  { TWeek }

  TWeek = record
  public
    function AddedDay(aDay: TDay): Boolean;
    function GetDayCount: Integer;
    function RemovedDay(aDay:TDay): Boolean;
    procedure Init;
    procedure Report;
  private
    case Boolean of
      True:  (days: TDays);
      False: (dwrd: DWord);
  end;

{ TWeek }

procedure TWeek.Init;
begin
  days := [];
end;

procedure TWeek.Report;
var
  d: TDay;
  s, ss: String;
begin
  ss := '[';
  case GetDayCount of
    0: begin
        ss := ss + ']';
        WriteLn(ss, ' week is empty');
        Exit;
    end
    else for d in TDay do
      if (d in days) then
        begin
          WriteStr(s, d);
          s := s + ', ';
          ss := ss + s;
        end;
      Delete(ss, Pred(Length(ss)), 2);
      ss := ss + ']';
    WriteLn(ss,', day count = ',GetDayCount);
  end;
end;

function TWeek.AddedDay(aDay: TDay): Boolean;
begin
  case aDay in days of
    True: Exit(False);
    False: begin
             Include(days, aDay);
             Result := True;
           end;
  end;
end;

function TWeek.RemovedDay(aDay: TDay): Boolean;
begin
  case aDay in days of
    True: begin
            Exclude(days, aDay);
            Result := True;
          end;
    False: Exit(False);
  end;
end;

function TWeek.GetDayCount: Integer;
begin
  Exit(PopCnt(dwrd));
end;

var
  d: TDay;
  week: TWeek;

begin
  with week do
    begin
      WriteLn(' initialising week record');
      Init;
      Report;

      d := dMon;
        WriteLn(' adding ',d);
        AddedDay(d);
        Report;

      d := dThu;
        WriteLn(' adding ', d);
        AddedDay(d);
        Report;

      d := dTue;
        WriteLn(' adding ', d);
        AddedDay(d);
        Report;

      d:= dSat;
        Writeln(' removing ', d);
        if RemovedDay(d) then
          Report
        else WriteLn('day ',d,' is not in the week record, so was not removed');

      d := dMon;
        WriteLn(' removing ', d);
        if RemovedDay(d) then
          Report
        else WriteLn('day ',d,' is not in the week record, so was not removed');
    end;
  WriteLn;
  WriteLn('Press [Enter] to finish');
  ReadLn;
end.
« Last Edit: December 04, 2018, 10:41:03 am by howardpc »

Yukiko

  • New member
  • *
  • Posts: 27
Thank you GetMem. I saw the PopCnt function posted elsewhere on the forums, of course after I had written my function :P I had been working on this scheduler for too long yesterday so I did not try it then.

Thank you, Wp. It's been years since I worked with sets. I had forgotten to just check for an empty set. I've been programming in a limited language that does not have a set type but treats arrays like sets. So I am relearning what little I knew about Pascal. Fortunately, the other language is "Pascalesque" so I have not had to relearn everything.

Howardpc, Wow! When you said "Here's a fuller example'" you were not kidding. :)
Thank you. I might steal your code or some of it anyway.

Again, and you are going to get tired of hearing this, thanks to the community and the developers of Lazarus and Free Pascal. It is a beautiful language and it's good to see it is still alive and thriving.