I have made a simplified demo (with a pseudo structure) to illustrate what I need:
type
TMyRec = record
GroupID: Integer;
Color: TColor;
end;
TMyRecArray = array of TMyRec;
My input array/list elements consists of non zero GroupIDs. They always grouped by GroupID (but not sorted and cannot be sorted):
GroupID
-------
2
2
2
1
1
3
3
etc...
each element has a Color. My output should be grouped by GroupIDs and should look like this (Where each group is either clRed/clGreen - alternating in turn):
GroupID ; Color
------- -----
2 ; clRed
2 ; clRed
2 ; clRed
1 ; clGreen
1 ; clGreen
3 ; clRed
3 ; clRed
etc...
9 ; clGreen
7 ; clRed
7 ; clRed
I use the code:
procedure TForm1.Button1Click(Sender: TObject);
var
R: TMyRecArray;
I: Integer;
S: string;
OldId: Integer;
begin
// populate some data
SetLength(R, 7);
R[0].GroupID := 2;
R[1].GroupID := 2;
R[2].GroupID := 2;
R[3].GroupID := 1;
R[4].GroupID := 1;
R[5].GroupID := 3;
R[6].GroupID := 3;
OldId := 0;
for I := 0 to High(R) do
begin
if OldId <> R[I].GroupID then
begin
OldId := R[I].GroupID;
R[I].Color := clRed;
end
else
begin
R[I].Color := clGreen;
end;
end;
Memo1.Clear;
for I := 0 to High(R) do
begin
ColorToIdent(R[I].Color, S);
Memo1.Lines.Add(Format('%d ; %s', [R[I].GroupID, S]));
end;
end;
And the result is NOT correct:
2 ; clRed
2 ; clGreen
2 ; clGreen
1 ; clRed
1 ; clGreen
3 ; clRed
3 ; clGreen
What am I missing? I know the solution is simple but I just can't put my mind on it.
Limitations: I can only iterate once; I cannot read ahead/previous records.
"Divide and conquer." You can separate gathering of attributes and applying the coloring, from the decision making.
OldId := 0; GroupNo := 0;
for I := Low(R) to High(R) do
begin
if (OldId <> R[I].GroupId) or (GroupNo = 0) then
begin
OldId := R[I].GroupId;
Inc(GroupNo);
ItemNo := 0;
end;
Inc(ItemNo);
R[I].Color := GroupColor(OldId, GroupNo, ItemNo);
end;
Then you can focus on the choice itself without overflowing your mind with details about actual coloring, data iteration and else. That also would give you more flexibility of what do you actually need. GroupColor may even be a variable, implementing different highlighting patterns according to setup.
Do you want alternating colors group after groups ?
function GroupColor(const Id, Number, Item: integer): TColor;
begin
if Odd(Number)
then Result := clRed
else Result := clGreen
end;
Or do you want different groups have different colors ?
function GroupColor(const Id, Number, Item: integer): TColor;
begin
case Id of
1: Result := clRed;
2: Result := clYellow;
3: Result := clBlue;
4: Result := clGreen;
else Result := clWhite;
end;
end;
Or do you want to stress the tops, leaders of each group ?
function GroupColor(const Id, Number, Item: integer): TColor;
begin
case Item of
1: Result := clRed;
2: Result := clYellow;
3: Result := clGreen;
else Result := clGray;
end;
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With