首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >这样经济吗?

这样经济吗?
EN

Stack Overflow用户
提问于 2015-10-26 06:03:14
回答 3查看 242关注 0票数 1

只是想看看是否有更好的方法来执行以下操作(对于所有事情总是有更好的方法),因为在加载数据时,它确实会延迟应用程序。

我想用存储在csv文件中的数据填充一个记录数组,目前我已经为这个数组设置了固定的长度,但是稍后我会使它成为动态的,这样我就可以添加到csv文件中了。

代码语言:javascript
复制
    type
          TStarCoords = Packed record
            szSystem: String[40];
            fCoordX: Single;
            fCoordY: Single;
            fCoordZ: Single;
          end;

    SystemCoords: Array [0 .. 22379] of TStarCoords;

Const
SYSTEMS = 'Data\Systems.csv';

然后填充oncreate事件上的数组。

代码语言:javascript
复制
procedure TForm1.FormCreate(Sender: TObject);
var
  szFile, sRecord: string;
  Row, Index, i: Integer;
  slList: TStringList;
begin

  szFile := ExtractFilePath(ParamStr(0)) + SYSTEMS;

  if FileExists(szFile) then
    try
      slList := TStringList.Create;
      slList.LoadFromFile(szFile);

      for Row := 0 to slList.Count - 1 do
      begin
        sRecord := slList[Row];

        index := Pos(',', sRecord);
        if index > 0 then
        begin
          SystemCoords[Row].szSystem := Copy(sRecord, 1, index - 1);
          Delete(sRecord, 1, index);
        end;

        index := Pos(',', sRecord);
        if index > 0 then
        begin
          SystemCoords[Row].fCoordX := StrToFloat(Copy(sRecord, 1, index - 1));
          Delete(sRecord, 1, index);
        end;

        index := Pos(',', sRecord);
        if index > 0 then
        begin
          SystemCoords[Row].fCoordY := StrToFloat(Copy(sRecord, 1, index - 1));
          Delete(sRecord, 1, index);
        end;

        SystemCoords[Row].fCoordZ := StrToFloat(sRecord);
      end;
    finally
      slList.Free;
    end;

  for i := Low(SystemCoords) to High(SystemCoords) do
  begin
    cbSystem.Items.Add(SystemCoords[i].szSystem);
  end;
end;

正如您所看到的,我正在使用"Pos“函数解析csv文件,并在末尾循环数组以将星号添加到组合框中,这样做更经济吗?

欢迎任何建议。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-10-26 14:27:20

就像其他人说的,很可能大部分的时间都花在填充组合上。

在我看来,在处理TStrings的大更新时,Jens Borrisholt's answer提出的BeginUpdate / EndUpdate技术是一种有效的方法。

作为一个小问题,如果您的应用程序是唯一写入和读取数据的应用程序,而且计算机和人类都不关心CSV格式,那么您可以考虑使用BlockReadBlockWrite函数存储采用不同文件格式的记录。

代码语言:javascript
复制
type
  TStarCoords = record
    szSystem: string[40];
    fCoordX,
    fCoordY,
    fCoordZ: Single;
  end;

。。。

代码语言:javascript
复制
const
  CFILENAME = '<your path to some file .dat>';

读取数据:

代码语言:javascript
复制
procedure TForm1.FormCreate(Sender: TObject);
var
  lstStarCoords: TList<TStarCoords>;
  f: File;
  starCoords: TStarCoords;
begin
  lstStarCoords := TList<TStarCoords>.Create;
  try

    AssignFile(f, CFILENAME);
    Reset(f, SizeOf(TStarCoords));
    try
      while not Eof(f) do begin
        BlockRead(f, starCoords, 1);
        lstStarCoords.Add(starCoords);
      end;
    finally
      CloseFile(f);
    end;

    cbSystem.Items.BeginUpdate;
    for starCoords in lstStarCoords do
      cbSystem.Items.Add(starCoords.szSystem);
    cbSystem.Items.EndUpdate;

  finally
    lstStarCoords.Free;
  end;
end;

编写数据:

代码语言:javascript
复制
procedure TForm1.WriteStarCoords;
var
  lstStarCoords: TList<TStarCoords>;
  f: File;
  starCoords: TStarCoords;
  i: Integer;
begin
  lstStarCoords := TList<TStarCoords>.Create;
  try

    //let's insert 5k new items
    for i:=1 to 5000 do begin
      with starCoords do begin
        szSystem := 'HYEL YE';
        fCoordX := 122;
        fCoordY := 12.375;
        fCoordZ := 45.75;
      end;
      lstStarCoords.Add(starCoords);
    end;

    AssignFile(f, CFILENAME);
    Rewrite(f, SizeOf(TStarCoords));
    try
      for starCoords in lstStarCoords do
        BlockWrite(f, starCoords, 1);
    finally
      CloseFile(f);
    end;

  finally
    lstStarCoords.Free;
  end;
end;

编辑:示例使用指针将记录信息直接存储在cbSystem组件中。

这种方法有点“危险”,因为它分配的内存必须手动释放,但允许避免使用TDictionaryTStarCoords.szSystem与相应的记录配对。

声明指向TStarCoords记录的新类型:

代码语言:javascript
复制
type
  PStarCoords = ^TStarCoords;

读取数据:

代码语言:javascript
复制
procedure TForm1.FormCreate(Sender: TObject);
var
  lstStarCoords: TStringList;
  f: File;
  starCoords: PStarCoords;
begin
  ClearCbSystem;

  lstStarCoords := TStringList.Create(False);
  {another minor enhancement:
   since lstStarCoords does not own any TObject which needs to be freed
   the OwnsObjects property of the TStringList can be set to False
   in order to avoid some code to be execute in some method like Clear and Delete}
  try

    lstStarCoords.BeginUpdate;

    AssignFile(f, CFILENAME);
    Reset(f, SizeOf(TStarCoords));
    try
      while not Eof(f) do begin
        New(starCoords);
        BlockRead(f, starCoords^, 1);
        lstStarCoords.AddObject(starCoords^.szSystem, TObject(starCoords));
      end;
    finally
      CloseFile(f);
    end;

    lstStarCoords.EndUpdate;

    cbSystem.Items.Assign(lstStarCoords);
  finally
    lstStarCoords.Free;
  end;
end;

使用cbSystem.Clear清除列表不会自动释放必须手动释放的底层指针。每次必须清除ClearCbSystem列表时都使用cbSystem过程:

代码语言:javascript
复制
procedure TForm1.ClearCbSystem;
var
  i: Integer;
begin
  cbSystem.Items.BeginUpdate;
  for i := cbSystem.Items.Count-1 downto 0 do
    Dispose(PStarCoords(cbSystem.Items.Objects[i]));
  cbSystem.Clear;
  cbSystem.Items.EndUpdate;
end;

当表单被销毁时,对ClearCbSystem过程的调用确保在应用程序本身释放cbSystem组件之前释放指针:

代码语言:javascript
复制
procedure TForm1.FormDestroy(Sender: TObject);
begin
  ClearCbSystem;
end;
票数 2
EN

Stack Overflow用户

发布于 2015-10-26 09:08:39

看上去不太有效率。

  • 分配固定长度的全局数组看起来很差。使用在运行时确定的动态长度数组。
  • 不建议使用短字符串。不要在现代编程中使用它们。它们是遗留的,不处理Unicode。
  • 别打包记录。这会导致数据不对齐。
  • 似乎需要更多的堆分配。如果可以的话,尽量避免Delete
  • 加载到字符串列表中是不有效的。使用基于行读取器的速度方法。不过,特尔斐在课堂上建的是垃圾。如果你想要速度和有效地使用记忆,那就自己滚吧。
  • 可能大部分时间都花在填充组合上了!向组合中添加22380项将花费很长的时间。别干那事。如果数据集较小,则只添加数据中的项目。否则,在UI控件中使用虚拟范例。

不过,下一步是找出瓶颈所在。我们只能猜测,因为我们缺少了那么多信息。我们不知道数据是否是静态的,它有多大,等等。

票数 4
EN

Stack Overflow用户

发布于 2015-10-26 06:50:16

您可以使用TStringlist对行进行解析。在下面的文章中,我假设您的元素由逗号分隔。

由于您要将您的记录的字符串表示放入一个组合框中,所以以后在您的程序中需要换一种方式:从字符串中找到一个TStarCoords。假设我引用了您将元素放入TDictionary中的示例,请安装一个数组。

代码语言:javascript
复制
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Generics.Collections, StdCtrls;

type
  TStarCoords = packed record
    szSystem: string[40];
    fCoordX: Single;
    fCoordY: Single;
    fCoordZ: Single;
  end;
const
  SYSTEMS = 'Data\Systems.csv';

type
  TForm1 = class(TForm)
    ComboBox1: TComboBox;
    procedure FormCreate(Sender: TObject);
    procedure ComboBox1Change(Sender: TObject);
  private
    SystemCoords: TDictionary<string, TStarCoords>;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ComboBox1Change(Sender: TObject);
var
  StarCoord: TStarCoords;
begin
  if not SystemCoords.TryGetValue(ComboBox1.Text, StarCoord) then
    exit; //todo : Make some error handling

  Caption := FloatToStr(StarCoord.fCoordX);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  Lines, Elements: TStringlist;
  Line: string;
  SystemCoord: TPair<string, TStarCoords>;
begin
  if not FileExists(ExtractFilePath(ParamStr(0)) + SYSTEMS) then
    exit; //todo: Some error handling

  SystemCoords := TDictionary<string, TStarCoords > .Create;
  Lines := TStringlist.Create;
  Elements := TStringlist.Create;
  Elements.LineBreak := ',';
  try
    for Line in Lines do
    begin
      Elements.Text := Line;

      SystemCoord.Key := Elements[0];
      with SystemCoord.Value do
      begin
        szSystem := string(Elements[0]);
        fCoordX := StrToFloat(Elements[1]);
        fCoordY := StrToFloat(Elements[2]);
        fCoordZ := StrToFloat(Elements[3]);
      end;

      SystemCoords.Add(SystemCoord.Key, SystemCoord.Value);
    end;

  finally
    Lines.Free;
    Elements.Free;
  end;

  try
    ComboBox1.Items.BeginUpdate;
    for SystemCoord in SystemCoords do
      ComboBox1.Items.Add(SystemCoord.Key);
  finally
    ComboBox1.Items.EndUpdate;
  end;

end;

end.
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33339366

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档