Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2017-07

If vs case or something else?

6 messages · 4 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

James Richters

I'm trying to optimize a console application ported over from Turbo Pascal with a huge set of if then else statements like this:

Var
     TXT : String;
If TXT = 'Thing1' then
   Begin
      Dosomething();
      DoSomethingelse();
   End
else
If TXT = 'AnotherThing' then
   Begin
      Dosomethinganotherway();
      DoSomethingelsetoo();
   End
Else
If TXT = 'Thing3' then
   Begin
      Dosomethingathirdtime();
      DoSomethingelse3();
   End
else   .... etc..  over 70 times... etc

It works but it's hard to follow and not so fast. It has to run through this for every line of a file to see what's in the file and do the right things with it. So I'm thinking of undertaking a huge re-organization of it and I'm wondering what the best way would be to do it.

I can use case statement with strings apparently now, but the thing is, I create this file myself in an earlier stage, so I do not need to create the file with strings at all, I could use some codes and do something like this:

Const
   Thing1 = 1
    Another_Thing = 2
    Thing3 = 3
Var
    Codenum: Word;

Case Codenum of
Thing1: Begin
DoSomethng()
DoSomethingElse()

       End;
    Another_Thing: Begin

... etc ...

I'm guessing that would be faster as I wouldn't have to keep evaluating all the strings for every condition. As I was searching for the best way to do this, I came across something about making an Array of Procedures, or something to that effect. Does anyone know how to do that, and are there performance advantages to doing that? It's going to take a bit of work to straighten all this out so it would be best if I just did it the best way instead of doing it one way then finding out it could have been better another way. Any other ideas on how to handle this?

Any advice on this is greatly appreciated

James

Reply by email

Sven Barth
to James Richters
James Richters wrote
I can use case statement with strings apparently now, but the thing is, I create this file myself in an earlier stage, so I do not need to create the file with strings at all, I could use some codes and do something like this:

"case of String" is essentially the same as your chain of if-statements, the compiler doesn't do any real optimization there.

Show quoted text 19 lines
Const Thing1 = 1 Another_Thing = 2 Thing3 = 3 Var Codenum: Word; Case Codenum of Thing1: Begin DoSomethng() DoSomethingElse() End; Another_Thing: Begin ... etc ... I'm guessing that would be faster as I wouldn't have to keep evaluating all the strings for every condition. As I was searching for the best way to do this, I came across something about making an Array of Procedures, or something to that effect. Does anyone know how to do that, and are there performance advantages to doing that? It's going to take a bit of work to straighten all this out so it would be best if I just did it the best way instead of doing it one way then finding out it could have been better another way. Any other ideas on how to handle this? Any advice on this is greatly appreciated

If you aren't fixed on having to work on a string that would definitely be best as you could then use a enum or something like that and you a case statement. The compiler will try to pick a suitable implementation then (jumptable, linear search), depending on the amount of labels.

Alternatively you can indeed use an array of procedures like this:

=== code begin ===

program tprocarray;
procedure Proc1;
begin
  Writeln('Proc1');
end;
procedure Proc2;
begin
  Writeln('Proc2');
end;

const
Procs: array[0..1] of TProcedure = (
@Proc1,
@Proc2

  );
var
  proc: Longint;
begin
  proc := 1;
  Procs[proc]();
end.

=== code end ===

Of course you can also use an enum as the array index:

=== code begin ===

{$scopedenums on} // just for demonstrations

type
TProcs = (
One,
Two

  );

const
Procs: array[TProcs] of TProcedure = (
@Proc1,
@Proc2

  );
var
  proc: TProcs;
begin
  proc := TProcs.Two;
  Procs[proc]();
end.

=== code end ===

The variant with the enum has the advantage that the compiler will complain about missing elements if you add one to the enum type.

Though in both cases you should ensure that your index is in range.

In case of many branches the variant with the array (any of the two variants) should be faster than the case one.

Regards,
Sven

Reply by email

Stefan V. Pantazi
to James Richters: I'm trying to optimize a console application ported over from Turbo Pascal with a huge…

That is quite the case statement you have there. You may benefit greatly from re-analyzing and refactoring your programs by splitting them in multiple individual units, if possible. That should be perfectly possible if Dosomething(); DoSomethingelse(); keep repeating across your 70+ switch cases.

Anyway, here you go, you can try something like the attached.

Good luck!

Stefan

James Richters wrote 57 lines
I'm trying to optimize a console application ported over from Turbo Pascal with a huge set of if then else statements like this: Var TXT : String; If TXT = 'Thing1' then Begin Dosomething(); DoSomethingelse(); End else If TXT = 'AnotherThing' then Begin Dosomethinganotherway(); DoSomethingelsetoo(); End Else If TXT = 'Thing3' then Begin Dosomethingathirdtime(); DoSomethingelse3(); End else .... etc.. over 70 times... etc It works but it's hard to follow and not so fast. It has to run through this for every line of a file to see what's in the file and do the right things with it. So I'm thinking of undertaking a huge re-organization of it and I'm wondering what the best way would be to do it. I can use case statement with strings apparently now, but the thing is, I create this file myself in an earlier stage, so I do not need to create the file with strings at all, I could use some codes and do something like this: Const Thing1 = 1 Another_Thing = 2 Thing3 = 3 Var Codenum: Word; Case Codenum of Thing1: Begin DoSomethng() DoSomethingElse() End; Another_Thing: Begin ... etc ... I'm guessing that would be faster as I wouldn't have to keep evaluating all the strings for every condition. As I was searching for the best way to do this, I came across something about making an Array of Procedures, or something to that effect. Does anyone know how to do that, and are there performance advantages to doing that? It's going to take a bit of work to straighten all this out so it would be best if I just did it the best way instead of doing it one way then finding out it could have been better another way. Any other ideas on how to handle this? Any advice on this is greatly appreciated James _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
_______________________________________________________

Reply by email

Ched
to Stefan V. Pantazi

Hi Stefan,

You can skip large blocks of tests coding like this

If Length(txt)>0 then
    case txt[1] of
       'a': if txt='another' then
               ...
            else if txt='anum' then
               ...;
       'b': if txt="bubble' then
               ...
            else if ...
    else
       ...
    end;

Not as fast as a tree search balanced with probabilities (no answer to my question on the list afew days ago...), but probably ten time faster then what you proposed.

Cheers, Ched'

Stefan V. Pantazi wrote 87 lines
That is quite the case statement you have there. You may benefit greatly from re-analyzing and refactoring your programs by splitting them in multiple individual units, if possible. That should be perfectly possible if Dosomething(); DoSomethingelse(); keep repeating across your 70+ switch cases. Anyway, here you go, you can try something like the attached. Good luck! Stefan On 07/06/2017 12:33 PM, James Richters wrote: > I'm trying to optimize a console application ported over from Turbo Pascal with a huge set of if then > else statements like this: > > Var > TXT : String; > If TXT = 'Thing1' then > Begin > Dosomething(); > DoSomethingelse(); > End > else > If TXT = 'AnotherThing' then > Begin > Dosomethinganotherway(); > DoSomethingelsetoo(); > End > Else > If TXT = 'Thing3' then > Begin > Dosomethingathirdtime(); > DoSomethingelse3(); > End > else .... etc.. over 70 times... etc > > It works but it's hard to follow and not so fast. It has to run through this for every line of a file > to see what's in the file and do the right things with it. > So I'm thinking of undertaking a huge re-organization of it and I'm wondering what the best way would > be to do it. > > I can use case statement with strings apparently now, but the thing is, I create this file myself in > an earlier stage, so I do not need to create the file with strings at all, I could use some codes and > do something like this: > > Const > Thing1 = 1 > Another_Thing = 2 > Thing3 = 3 > Var > Codenum: Word; > > Case Codenum of > Thing1: Begin > DoSomethng() > DoSomethingElse() > End; > Another_Thing: Begin > ... etc ... > > > I'm guessing that would be faster as I wouldn't have to keep evaluating all the strings for every > condition. As I was searching for the best way to do this, I came across something about making an > Array of Procedures, or something to that effect. Does anyone know how to do that, and are there > performance advantages to doing that? It's going to take a bit of work to straighten all this out so > it would be best if I just did it the best way instead of doing it one way then finding out it could > have been better another way. Any other ideas on how to handle this? > > Any advice on this is greatly appreciated > > James > > > > > _______________________________________________ > fpc-pascal maillist - > http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal > _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal

Reply by email

Stefan V. Pantazi
to Ched

I am not sure I follow. If switching on strings, or any sparse value set, you can use the balanced tree approach or better yet, a hash table. But when switching on a compact, limited set of integer values (as the case seems to be), I do not see how you can compete with constant time procedure table/array lookups.

Stefan

Show quoted text 109 lines
You can skip large blocks of tests coding like this Not as fast as a tree search balanced with probabilities (no answer to my question on the list afew days ago...), but probably ten time faster then what you proposed. Cheers, Ched' Le 06.07.2017 à 20:41, Stefan V. Pantazi a écrit : > That is quite the case statement you have there. You may benefit > greatly from re-analyzing and refactoring your programs by splitting > them in multiple individual units, if possible. That should be > perfectly possible if Dosomething(); DoSomethingelse(); keep > repeating across your 70+ switch cases. > > Anyway, here you go, you can try something like the attached. > > Good luck! > > Stefan > > > > On 07/06/2017 12:33 PM, James Richters wrote: >> I'm trying to optimize a console application ported over from Turbo >> Pascal with a huge set of if then else statements like this: >> >> Var >> TXT : String; >> If TXT = 'Thing1' then >> Begin >> Dosomething(); >> DoSomethingelse(); >> End >> else >> If TXT = 'AnotherThing' then >> Begin >> Dosomethinganotherway(); >> DoSomethingelsetoo(); >> End >> Else >> If TXT = 'Thing3' then >> Begin >> Dosomethingathirdtime(); >> DoSomethingelse3(); >> End >> else .... etc.. over 70 times... etc >> >> It works but it's hard to follow and not so fast. It has to run >> through this for every line of a file to see what's in the file and >> do the right things with it. >> So I'm thinking of undertaking a huge re-organization of it and I'm >> wondering what the best way would be to do it. >> >> I can use case statement with strings apparently now, but the thing >> is, I create this file myself in an earlier stage, so I do not need >> to create the file with strings at all, I could use some codes and do >> something like this: >> >> Const >> Thing1 = 1 >> Another_Thing = 2 >> Thing3 = 3 >> Var >> Codenum: Word; >> >> Case Codenum of >> Thing1: Begin >> DoSomethng() >> DoSomethingElse() >> End; >> Another_Thing: Begin >> ... etc ... >> >> >> I'm guessing that would be faster as I wouldn't have to keep >> evaluating all the strings for every condition. As I was searching >> for the best way to do this, I came across something about making an >> Array of Procedures, or something to that effect. Does anyone know >> how to do that, and are there performance advantages to doing that? >> It's going to take a bit of work to straighten all this out so it >> would be best if I just did it the best way instead of doing it one >> way then finding out it could have been better another way. Any >> other ideas on how to handle this? >> >> Any advice on this is greatly appreciated >> >> James >> >> >> >> >> _______________________________________________ >> fpc-pascal maillist - >> http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal >> > > > > _______________________________________________ > fpc-pascal maillist - > http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal > _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
_______________________________________________________

Reply by email

James Richters
to Stefan V. Pantazi

Thank you Sven and Stefan for the advice and examples, I really appreciate it. I'll to some time tests with some sample programs and figure out which way to go with it. It seems at first glance that the array of procedures would be more complicated, but the more I think about it, the more I think it would actually be easier to manage and easier to follow than the insane list of if, then, else statements, and also easier to manage than a huge long case statement, I do have several other conditional statements within the big long if then else structure and sometime I mess up the entire thing by misplacing an end, or leaving one out... this would never be a problem with the array of procedures as the conditional statements inside the procedures would be well defined as they would not be mixed in with a huge list of if statements, and I might be able to combine many of the procedures and just pass them related arguments. It might also help organization with Units. Also thanks to Ched for the idea using a case statement on just the first character in a string then smaller case statements within that. I do have another situation where I needed to use string input and figure out what to do based on the string value and it seems this would save a lot of time.

James

Reply by email