- Mastering Delphi Programming:A Complete Reference Guide
- Primo? Gabrijel?i?
- 439字
- 2021-06-24 12:33:35
Extracting common expressions
This next tip will sound obvious, but it will nicely introduce us to the next topic. Plus, it is a real problem frequently found in production code.
The ExtractCommonExpression demo creates a list box with a mere 1,000 entries, all in the form Author–Title. A click on the Complicated expression button runs a short code which reverts the order of Author and Title in the list box so that it shows entries in the form Title–Author:
procedure TfrmCommonExpression.Button1Click(Sender: TObject);
var
i: Integer;
sw: TStopwatch;
begin
ListBox1.Items.BeginUpdate;
try
sw := TStopwatch.StartNew;
for i := 0 to ListBox1.Count - 1 do
ListBox1.Items[i] :=
Copy(ListBox1.Items[i], Pos('-', ListBox1.Items[i]) + 1,
Length(ListBox1.Items[i]))
+ '-'
+ Copy(ListBox1.Items[i], 1, Pos('-', ListBox1.Items[i]) - 1);
sw.Stop;
Button1.Caption := IntToStr(sw.ElapsedMilliseconds);
finally ListBox1.Items.EndUpdate; end;
end;
The code goes over the list and for each entry finds the '-' character, extracts the first and second part of the entry and combines them back together, reversed. It does that, however, in a terrible copy-and-paste way. The code refers to ListBox1.Items[i] five times while calculating the result. It also calls Pos('-', ListBox1.Items[i]) twice.
In a language with a really good compiler, you could expect that both subexpressions mentioned in the previous paragraph would be calculated only once. Not with Delphi's compiler, though. It has some optimization built in, but Delphi's optimization is far from the level required for such tricks to work. That leaves a burden of optimization on us, the programmers.
The second button in this demo executes the code shown next. This implementation of the same algorithm is not only more readable, but accesses ListBox1.Items[i] only once. It also calculates the position of '-' inside the string only once:
procedure TfrmCommonExpression.Button2Click(Sender: TObject);
var
i: Integer;
s: string;
p: Integer;
sw: TStopwatch;
begin
ListBox1.Items.BeginUpdate;
try
sw := TStopwatch.StartNew;
for i := 0 to ListBox1.Count - 1 do begin
s := ListBox1.Items[i];
p := Pos('-', s);
ListBox1.Items[i] := Copy(s, p + 1, Length(s)) + '-' +
Copy(s, 1, p - 1);
end;
sw.Stop;
Button2.Caption := IntToStr(sw.ElapsedMilliseconds);
finally ListBox1.Items.EndUpdate; end;
end;
Comparing both approaches shows a definite improvement in the second case. The first method uses around 40 ms and the second one around 30 ms, which is 25% faster. The code only times the inner for loop, not the updating of the list box itself, which takes the same time in both cases.
I can recap all this with a simple statement—Calculate every subexpression only once. Good advice but, still, don't exaggerate. Simple expressions, such as i+1 or 2*i are so cheap (in computing time) that extracting them in a subexpression won't speed up the code.
- 新媒體跨界交互設計
- FPGA從入門到精通(實戰篇)
- Android NDK Game Development Cookbook
- 電腦維護與故障排除傻瓜書(Windows 10適用)
- Effective STL中文版:50條有效使用STL的經驗(雙色)
- 電腦組裝、維護、維修全能一本通(全彩版)
- scikit-learn:Machine Learning Simplified
- 微型計算機系統原理及應用:國產龍芯處理器的軟件和硬件集成(基礎篇)
- Wireframing Essentials
- 圖解計算機組裝與維護
- Mastering Machine Learning on AWS
- Building Machine Learning Systems with Python
- 嵌入式系統設計大學教程(第2版)
- The Machine Learning Workshop
- 電腦組裝與維修實戰