views:

157

answers:

4

Hi All,

I have the following code. It looks ugly, if the value equals to one of the following value then do something.

var
  Value: Word;
begin
  Value := 30000;
  if (Value = 30000) or (Value = 40000) or (Value = 1) then
    do_something;
end;

I want to refactor the code as follows:

var
  Value: Word;
begin
  Value := 30000;
  if (Value in [1, 30000, 40000]) then // Does not work
    do_something;
end;

However, the refactored code does not work. I assume that a valid set in Delphi accepts only elements with type byte. If there any good alternative to refactor my original code (besides using case)?

+7  A: 

I think something like this?

case value of
  1, 30000, 40000: do_somthing
end;
Roald van Doorn
thanks, but as I have noted in my question, I want another alternative. Because using switch...case for such a logic looks not normal
stanleyxu2005
@stanleyxu2005. It's probably the most efficient. And, besides, when you start writing thing like this, there is a good chance that you might end up having to add an else or even an else if condition `if value in [.] do bla else if value in [..] do blabla else do blablabla`. In such a case, the case is the obvious choice.
François
After one day waiting for responses, I agree that using switch...case is the most acceptable solution.
stanleyxu2005
I completely read over that last part of your question, though I still think a case would be the best solution here, so I'm glad we agree. :-) Even though I also like TOndrej's answer.
Roald van Doorn
A: 

Not as succint as Roald's answer, but if you are set on using sets, you could do:

var
  Value: Word;
  IntegerSet: TIntegerSet;
begin
  Include(IntegerSet, 1);
  Include(IntegerSet, 30000);
  Include(IntegerSet, 40000);
  Value := 30000;
  if (Value in IntegerSet) then
    DoSomething;
end;

The Include's are of course a hinderance, but could have been set elsewhere (making them reusable):

procedure CheckAndDo(const aValue: Integer; const aCheckAgainst: TIntegerSet);
begin
  if (aValue in aCheckAgainst) then
    DoSomethingComplicated;
end;

procedure DoIt;
var
  CheckValues: TIntegerSet;
begin
  Include(CheckValues, 1);
  Include(CheckValues, 30000);
  Include(CheckValues, 40000);
  //...
  CheckAndDo(30000, CheckValues);
end;
Marjan Venema
-1. The point of the question is that you *can't* use sets because sets can't hold the values being worked with. *If* sets worked in this situation, then we could just assign the whole things at once without using Include: `CheckValues := [1, 30000, 40000]`.
Rob Kennedy
@Rob: I don't share your interpretation. And because of the posters "I assume that a valid set in Delphi accepts only elements with type byte." I wanted to point out that there are sets in Delphi that can contain integer values, you just can't give them a value in a single "const" statement if the values in that statement are outside of the normal sets range.
Marjan Venema
@Marjan - if that's the TIntegerSet in "sysutils.pas" it is "set of 0..SizeOf(Integer) * 8 - 1;", as you can see it is a set of [0..31]. It is intented to be a set of "one" integer (its bits).
Sertac Akyuz
@Sertac: oh shucks of course, including the 30000 and 40000 wouldn't do what the poster wanted. Complete brain-rewiring necessary. Sets in Delphi are still not limited to byte [0..7], but it would be completely silly to declare a set with enough bits to distinguish up to 40000 individual settings...
Marjan Venema
+6  A: 

How about using an open array?

function ValueIn(Value: Integer; const Values: array of Integer): Boolean;
var
  I: Integer;
begin
  Result := False;
  for I := Low(Values) to High(Values) do
    if Value = Values[I] then
    begin
      Result := True;
      Break;
    end;
end;

Example (pseudo-code):

var
  Value: Integer;
begin
  Value := ...;
  if ValueIn(Value, [30000, 40000, 1]) then
    ...
end;
TOndrej
+1, Nice one, I like the reusability and cleanness.
Roald van Doorn
A: 

There is a class for larger bitsets, see Classes.TBits.

While it won't do constant expressions easily, it can be useful in certain other cases.

Marco van de Voort