Вставьте данные DBGrid в многомерный массив

Я установил соединение из Delphi в pgsql, используя ADOConnection, ADOQuery, DataSource и DBGrid, чтобы представить результаты моего запроса. База данных содержит 2 столбца значений типа double из нескольких тысяч строк, которые я хотел бы вставить в двумерный массив. Однако, поскольку я совершенно новый, я не знаю, как вставить содержимое DBGrid в массив. Любая помощь очень ценится.


person Elena_K    schedule 19.06.2014    source источник
comment
Как вы решаете, какой из двух столбцов типа Double хранить в массиве? Вместо того, чтобы смотреть на DBGrid, вам лучше посмотреть на свойство ADOQuery.FieldByName('Field1').AsDouble и использовать его для заполнения вашего массива.   -  person Andy_D    schedule 19.06.2014
comment
Вы никогда не читаете данные (и не записываете их) из TDBGrid; вместо этого получить доступ к базовым полям набора данных. TDBGrid предназначен для презентации и не более того.   -  person Ken White    schedule 19.06.2014
comment
Да, я уже понял это, но проблема в том, что у меня нет опыта, чтобы узнать, как лучше всего это сделать, и нет никакого источника, который мог бы ответить на мой вопрос. Если бы вы хотели производить вычисления с полями из вашей базы данных, что бы вы сделали? Вам нужно будет прочитать их и написать новые поля. Использование массивов может быть способом сделать это, но я застрял.   -  person Elena_K    schedule 19.06.2014
comment
Я думаю, что вы задаете неправильный вопрос и стремитесь к неправильному решению. если вам нужно рассчитать что-то, связанное с БД, используйте решение БД вместо многомерного массива. например у вас есть функция SUM в SQL; вы можете использовать вычисляемые/агрегированные поля в подчиненном TDataSet; и так далее...   -  person kobik    schedule 24.06.2014
comment
Может быть, вы могли бы рассказать нам, зачем вам нужен этот массив, и мы могли бы дать вам лучший ответ. Как вы сами указали, вам не хватает опыта работы с Delphi, и вы можете выбрать неправильный путь в качестве своего решения.   -  person AlexSC    schedule 24.06.2014
comment
Я хотел бы произвести расчеты, используя записи данных из моей базы данных. Лучший способ, который я мог придумать, это сначала перенести эти значения (около 8000 строк) в один (многомерный) массив. Например Если массив равен M(i,j), он будет похож на M(1,1)*M(1,2) для i-->n. ХТН   -  person Elena_K    schedule 26.06.2014


Ответы (1)


Прежде всего, если есть тысячи строк, вам нужно назначить поля переменным перед чтением, чтобы избавиться от ненужного времени поиска текста при использовании FieldByName.

У меня нет под рукой Delphi, но это должно сработать или, по крайней мере, помочь вам начать работу.

uses Math;

procedure ProcessArray(ADataSet: TDataSet);
var
  field1: TField;
  field2: TField;
  len: Integer;
  a: array of array[2] of double;
begin
  len := 0;
  SetLength(a, 0);
  field1 := ADataSet.FieldByName('field1');
  field2 := ADataSet.FieldByName('field2');
  ADataSet.First;
  while not ADataSet.Eof do
  begin
    Inc(len);
    if len > Length(a) then
      SetLength(a, len + Min(len, 16384));
    a[len - 1][0] := field1.Value;
    a[len - 1][1] := field2.Value;
    ADataSet.Next;
  end;
  SetLength(a, len);
  // Process the results in the a array
end;

AlexSC предлагает использовать свойство TADODataSet.RecordCount для первоначальной установки размера массива. Обратите внимание, что если TDataSet загружается из базы данных не полностью (например, использует серверный курсор), RecordCount не обязательно будет содержать количество всех записей, и оригинальное решение, приведенное выше, сможет справиться с этим. Я внес в него поправку, чтобы он не увеличивал более 16 000 элементов одновременно, а накладные расходы составляли не более 16 000 – 1 элементов массива. Для получения информации о «ленивой загрузке» TDataSet см. DBGrid с возможностью упреждающего чтения с использованием ADO< /а>

Пожалуйста, найдите код, используя RecordCount ниже:

procedure ProcessArray(ADataSet: TDataSet);
var
  field1: TField;
  field2: TField;
  len: Integer;
  a: array of array[2] of double;
begin
  len := 0;
  SetLength(a, ADataSet.RecordCount);
  field1 := ADataSet.FieldByName('field1');
  field2 := ADataSet.FieldByName('field2');
  ADataSet.First;
  while not ADataSet.Eof do
  begin
    a[len][0] := field1.Value;
    a[len][1] := field2.Value;
    Inc(len);
    ADataSet.Next;
  end;
  // Process the results in the a array here
end;
person too    schedule 19.06.2014
comment
Извините, я получаю ожидаемый идентификатор, но обнаружена ошибка ARRAY. Вероятно, потому что тип массива не может быть результатом функции? ... Есть ли способ без использования функции, это может усложнить ситуацию - person Elena_K; 19.06.2014
comment
@Elena_K: В любом случае вы должны предшествовать ADataSet.First и следовать за концом цикла While с помощью ADataSet.DisableControls и ADataSet.EnableControls соответственно, иначе вам, возможно, придется ждать целую вечность, пока прокручивается ваш DBGrid. - person MartynA; 19.06.2014
comment
Я просто изменил функцию на процедуру, чтобы ее можно было скомпилировать (хотя это еще не проверено). Вы можете добавить некоторый код обработки массива после комментария или просто переместить блок кода в свою функцию и добавить переменные в раздел объявления переменных вашей функции. - person too; 24.06.2014
comment
Я бы еще раз подумал о расширении массива во время цикла, особенно дублируя его каждый раз, когда это необходимо. Это приведет к экспоненциальному росту массива. Вместо этого я бы передал количество записей (набор данных имеет значение TADOQuery, поэтому мы можем использовать его свойство RecordCount) в качестве параметра и установил размер массива только один раз. - person AlexSC; 24.06.2014
comment
@ AlexSC Я вижу, что вместо этого я попробую использовать TADOQuery. Как это будет происходить в отношении поста тоже. Путь Too теперь не возвращает ошибку. Но я хотел бы посмотреть, как будет работать ADOQuery, а затем посмотреть, какое решение лучше. - person Elena_K; 26.06.2014