Модераторы: Snowy, MetalFan, bems, Poseidon

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Быстрая сортировка больших массивов данных, Наиболее быстрый метод сортировки 
:(
    Опции темы
Dementor
Дата 13.4.2012, 12:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 60
Регистрация: 9.7.2007

Репутация: нет
Всего: нет



Всем привет!

Опишу свою проблему, но сразу поясню - программированием давно не занимался (последний раз года полтора назад писал прогу для работы с xls и csv файлами).

Суть проблемы: есть массив данных в достаточно специфическом формате. Формат называется bin, используется для хранения данных лазерного сканирования в программе TerraScan (также las, fastbin и т.д.).

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

Что хочу реализовать - поиск одинаковых точек (одинаковые XYZ, например). Соответственно весь этот массив надо сортировать. Сортировка каким-нибудь пузырьком (воспоминания из универа) не подходит, т.к. массив может быть очень большой - десятки и сотни миллионов точек.
Не могли бы спецы подсказать - какой алгоритм позволит наиболее быстро обрабатывать такой большой массив данных.

Заранее огромное спасибо!!!!
PM MAIL   Вверх
kami
Дата 13.4.2012, 13:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Что в конечном итоге нужно сделать с этими точками? Просто узнать количество одинаковых, или после сортировки (кстати, не уверен, что она вообще сможет отработать) проанализировать дополнительные параметры каждой из одинаковых?
PM MAIL WWW   Вверх
Pretorian
Дата 13.4.2012, 13:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 57
Регистрация: 9.12.2011
Где: нигде

Репутация: нет
Всего: 1



PM   Вверх
Dementor
Дата 13.4.2012, 13:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 60
Регистрация: 9.7.2007

Репутация: нет
Всего: нет



Вообще предполагается написание проги, которая будет удалять точки с одинаковыми параметрами (например с одинаковыми координатами). Т.е. надо найти все точки с одинаковыми координатами и оставить только одну.
PM MAIL   Вверх
kami
Дата 13.4.2012, 13:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1806
Регистрация: 25.8.2007
Где: Санкт-Петербург

Репутация: 22
Всего: 72



Цитата(Pretorian @  13.4.2012,  13:05 Найти цитируемый пост)
есть Быстрая сортировка и Сортировка слиянием

(имхо) любые сортировки в памяти не актуальны с учетом 
Цитата(Dementor @  13.4.2012,  12:57 Найти цитируемый пост)
массив может быть очень большой - десятки и сотни миллионов точек.

С учетом кучи параметров каждой точки, это выйдет (как минимум) не одна сотня мегабайт. Слишком велика вероятность наткнуться на EOutOfMemory, и даже если (каким-то чудом) нет - бедный файл подкачки.
PM MAIL WWW   Вверх
Dementor
Дата 13.4.2012, 13:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 60
Регистрация: 9.7.2007

Репутация: нет
Всего: нет



Цитата(kami @  13.4.2012,  13:09 Найти цитируемый пост)
С учетом кучи параметров каждой точки, это выйдет (как минимум) не одна сотня мегабайт. Слишком велика вероятность наткнуться на EOutOfMemory, и даже если (каким-то чудом) нет - бедный файл подкачки. 

Да действительно, эти файлы достаточно велики по объему. По сути речь идет об обработке файлов от 10 до 500 мегабайт.

PM MAIL   Вверх
Qu1nt
Дата 13.4.2012, 13:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Хеш-таблица.
PM MAIL   Вверх
Pretorian
Дата 13.4.2012, 13:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 57
Регистрация: 9.12.2011
Где: нигде

Репутация: нет
Всего: 1



Цитата(Qu1nt @  13.4.2012,  15:16 Найти цитируемый пост)
Хеш-таблица.

что с ней делать?
PM   Вверх
Qu1nt
Дата 13.4.2012, 13:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Pretorian, данные из файла загрузить в хеш-таблицу. Дубликаты ликвидируются автоматически.
PM MAIL   Вверх
Pretorian
Дата 13.4.2012, 13:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 57
Регистрация: 9.12.2011
Где: нигде

Репутация: нет
Всего: 1



Qu1nt, хотел предложить подобный вариант, но думал, что структура которая отсекает двойников называется множеством (Set)

Это сообщение отредактировал(а) Pretorian - 13.4.2012, 13:29
PM   Вверх
Dementor
Дата 13.4.2012, 13:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 60
Регистрация: 9.7.2007

Репутация: нет
Всего: нет



Цитата(Qu1nt @  13.4.2012,  13:16 Найти цитируемый пост)
Хеш-таблица. 

Сижу, читаю. Буду пытаться это реализовать. Думаю сначала на маленьком примере из 100 точек попробую. Мне самому даже интересно не столько 100% реализация задуманного (все равно делаю можно сказать для себя), сколько понимаю того как это можно реализовать, а там уже подгоню и производительность.
PM MAIL   Вверх
Qu1nt
Дата 13.4.2012, 13:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Pretorian, множества обычно реализуют на основе хеш-таблиц.
Dementor, используй TDictionary из Generics.Collections.
PM MAIL   Вверх
Dementor
Дата 13.4.2012, 14:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 60
Регистрация: 9.7.2007

Репутация: нет
Всего: нет



Осмелюсь задать еще один вопрос.
Я как-то вообще с конца пошел...
А вопрос в следующем - как открыть файл с известной структурой?
Каким надо инструментом для этого пользоваться (предполагая работу с N числом файлов)? Соответственно, чтобы потом передать считанную инфу в TDictionary.
Могу привести структуру файла (Scan binary 16 bit line):
Код

typedef struct {
int HdrSize ; // sizeof(ScanHdr)
int HdrVersion ; // Version 20020715, 20010712, 20010129 or 970404
int RecogVal ; // Always 970401
char RecogStr[4]; // CXYZ
long PntCnt ; // Number of points stored
int Units ; // Units per meter = subpermast * uorpersub
double OrgX ; // Coordinate system origin
double OrgY ;
double OrgZ ;
int Time ; // 32 bit integer time stamps appended to points
int Color ; // Color values appended to points
} ScanHdr ;

Если объясните хотя бы примерно - буду очень благодарен.

Это сообщение отредактировал(а) Dementor - 13.4.2012, 14:46
PM MAIL   Вверх
Qu1nt
Дата 13.4.2012, 15:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



С помощью TBinaryReader читай только необходимые тебе поля.
PM MAIL   Вверх
Freimaks
Дата 14.4.2012, 08:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Цитата(Qu1nt @  13.4.2012,  13:40 Найти цитируемый пост)
С помощью TBinaryReader читай только необходимые тебе поля. 

Посидел, кое-что написал. Есть пара непонятных моментов, из-за которых все рушится. Пока я пытаюсь хотя бы считать данные из раздела Header (по сути мне от туда необходимо только одно поле):
Итак я объявляю все переменные:
Код

type TBinHeader = record
HdrSize: integer; // sizeof(ScanHdr)
HdrVersion: integer; // Version 20020715, 20010712, 20010129 or 970404
RecogVal: integer; // Always 970401
RecogStr: string[4]; // CXYZ
PntCnt: cardinal; // Number of points stored
Units: integer ; // Units per meter = subpermast * uorpersub
OrgX: double; // Coordinate system origin
OrgY: double;
OrgZ: double;
Time: integer; // 32 bit integer time stamps appended to points
Color: integer; // Color values appended to points
end;
var
  AFile: TFileStream;
  BR: TBinaryReader;
  BinHeader: TBinHeader;

Далее просто для того, чтобы понять чего я вообще получаю при чтении на выход я не только считываю, но и пишу все в memo
Код

begin
for ifiles:= 0 to ifilesall-1 do
  begin
  memo3.Lines.Clear;
AFile := TFileStream.Create(Opendialog1.Files.Strings[ifiles], fmOpenRead);
BR := TBinaryReader.Create(AFile, TEncoding.Default, false);
  try
    with BinHeader do
    begin
    HdrSize := BR.ReadInteger;
    memo3.Lines.Text:=memo3.Lines.Text+inttostr(HdrSize)+#13;
    HdrVersion := BR.ReadInteger;
    memo3.Lines.Text:=memo3.Lines.Text+inttostr(HdrVersion)+#13;
    RecogVal := BR.ReadInteger;
    memo3.Lines.Text:=memo3.Lines.Text+inttostr(RecogVal)+#13;
    RecogStr:= BR.ReadString;
    memo3.Lines.Text:=memo3.Lines.Text+RecogStr+#13;
    PntCnt:= BR.ReadCardinal;
    memo3.Lines.Text:=memo3.Lines.Text+inttostr(PntCnt)+#13;
    Units:= BR.ReadInteger;
    memo3.Lines.Text:=memo3.Lines.Text+inttostr(Units)+#13;
    OrgX:= BR.ReadDouble;
    memo3.Lines.Text:=memo3.Lines.Text+FloatToStr(OrgX)+#13;
    OrgY:= BR.ReadDouble;
    memo3.Lines.Text:=memo3.Lines.Text+FloatToStr(OrgY)+#13;
    OrgZ:= BR.ReadDouble;
    memo3.Lines.Text:=memo3.Lines.Text+FloatToStr(OrgZ)+#13;
    Time:= BR.ReadInteger;
    memo3.Lines.Text:=memo3.Lines.Text+inttostr(Time)+#13;
    Color:= BR.ReadInteger;
    memo3.Lines.Text:=memo3.Lines.Text+inttostr(Color)+#13;
    BR.Close;
    end;
  finally
    BR.Free;
    AFile.Free;
end;
end;

for ifiles:= 0 to ifilesall-1 do - отвечает за работу если открыто несколько файлов (указание на файлы идет через OpenDialog).
Что получаю на выходе:
Код

56
20020715
970401
XYZ
54659977
582504482
5.076967755524E-299
-1.16115830415237E-118
1.99379198448988E-141
11969
33619970

До строки XYZ(далее у меня какой-то крестик в memo) все верно - как в документации к файлу.
Строка "XYZ(какой-то крестик)" по сути должна иметь вид "CXYZ". А далее видимо все рушится из-за неправильной отработки этой части файла (а может и нет...).
И это я не дошел даже до рездела с точками (где структура еще хлеще).
Подскажите, чего я делаю не так???
PM MAIL   Вверх
Qu1nt
Дата 14.4.2012, 11:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



В общем случае можно выделить два подхода:
Частичное описание структуры. Целесообразно использовать для экономии памяти. 
Код

procedure ReadBinHeaderWithoutRecord(const FileName: String; Output: TStrings);
begin
  with TBinaryReader.Create(FileName) do
  try
    BaseStream.Seek(SizeOf(Integer) * 3, soCurrent);
    Output.Append(Format('RecogStr: %s', [TEncoding.ANSI.GetString(ReadBytes(4))]));
    BaseStream.Seek(SizeOf(Integer) * 2, soCurrent);
    BaseStream.Seek(SizeOf(Double) * 3, soCurrent);
    Output.Append(Format('Time: %d', [ReadInteger]));
  finally
    Free;
  end;
end;

Полное описание структуры. 
Код

procedure ReadBinHeaderWithRecord(const FileName: String; Output: TStrings);
var
  Header : packed record
    HdrSize: Integer;
    HdrVersion: Integer;
    RecogVal: Integer;
    RecogStr: array [0..3] of AnsiChar;
    PntCnt: Integer;
    Units: Integer;
    OrgX: Double;
    OrgY: Double;
    OrgZ: Double;
    Time: Integer;
    Color: Integer;
  end;
begin
  with TBinaryReader.Create(FileName) do
  try
    BaseStream.Read(Header, SizeOf(Header));
    Output.Append(Format('RecogStr: %s', [AnsiString(Header.RecogStr)]));
    Output.Append(Format('Time: %d', [Header.Time]));
  finally
    Free;
  end;
end;

В твоём случае ошибка заключается в том, что с помощью ReadString можно читать только те строки, которые записаны через WriteString. В этих методах сначала читается/записывается размер строки, а только потом данные.

PM MAIL   Вверх
Freimaks
Дата 14.4.2012, 13:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Да, предложенный способ оказался рабочим - Header считывается без проблем. Щас немного доработаю и попробую также считать точки. Хотя конечно далеко не все мне понятно в плане работы TBinaryReader
PM MAIL   Вверх
Qu1nt
Дата 14.4.2012, 13:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Тут два способа. Первый лучше применить к точкам, второй - к заголовку.
PM MAIL   Вверх
Freimaks
Дата 14.4.2012, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Да, я использовал второй (где полностью расписывается структура) для хедера.
Для точек он конечно подойдет, но как понимаю это будет очень тяжелый случай, т.к. точек очень много (хотя пока я пытаюсь прочесть небольшой файл, всего с 16 точками.
Как тока сумею их зачитать примусь за TDictionary.
Самое простое чего хочу пока добиться, это просто анализ информации о том, есть или нету одинаковых. Если уж это смогу сделать, то удаление\перенос уж точно реализую.

P.S. а за что отвечает в процедуре Output: TStrings??? Т.е. понятно, что позволяет использовать Output.Append(Format('Time: %d', [ReadInteger]));, но как его описывать при вызове процедуры?

В точках конечно структура сложнее
Код

Attribute                 Always      C Data Type  Size
Point coordinates   Yes            Point3d        12 bytes
Time stamps            -               double8 bytes
Group identifiers      -                unsigned int4 bytes
Normal vectors        -             unsigned int    4 bytes
Distances                -                 int                 4 bytes
RGB colors               -               RgbClr           3 bytes
Intensity values       -           unsigned short   2 bytes
Line numbers           -            unsigned short   2 bytes
Echo lengths           -              short   2 bytes
Parameter values    -               unsigned short   2 bytes
Point classes            Yes             unsigned char   1 byte
Mark values
-- run time only         Yes           unsigned char   1 byte
Flag values
-- run time only        Yes           unsigned char   1 byte
Scanner angles        -             char1 byte
Echo bits                  -            unsigned char   1 byte
Scanner numbers     -              unsigned char   1 byte
Echo normality values-             unsigned char1 byte


Это сообщение отредактировал(а) Freimaks - 14.4.2012, 13:32
PM MAIL   Вверх
Qu1nt
Дата 14.4.2012, 13:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Например
Код

ReadBinHeaderWithRecord('%path%', Memo1.Lines);

PM MAIL   Вверх
Freimaks
Дата 14.4.2012, 13:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



АААА, все понял. Я просто удалил его, понимая что он не очень важен, но не понимая, что он реально делает. Теперь усе понял!!!
PM MAIL   Вверх
Qu1nt
Дата 14.4.2012, 14:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Недостаточно информации. Неясно как определять наличие того или иного атрибута.
PM MAIL   Вверх
Freimaks
Дата 14.4.2012, 14:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Да, инфы мало. Сам сижу думаю, а как определить что есть какой-то атрибут из необязательных или его нет. В принципе многие из них по умолчанию есть, но от раза к разу могут добавляться или уходить...
PM MAIL   Вверх
Qu1nt
Дата 14.4.2012, 15:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Хм, а вот я нашел такие форматы:
Код

The structure of a point record for file version 20010712 is:
typedef struct 
{
BYTE Code ; // Classification code 0-255
BYTE Line ; // Flightline number 0-255
USHORT EchoInt ; // Intensity bits 0-13, echo bits 14-15
long X ; // Easting
long Y ; // Northing
long Z ; // Elevation
} ScanRow ;

The structure of a point record for file version 20020715 is:
typedef struct {
Point3d Pnt ; // Coordinates
BYTE Code ; // Classification code
BYTE Echo ; // Echo information
BYTE Flag ; // Runtime flag (view visibility)
BYTE Mark ; // Runtime flag
USHORT Line ; // Flightline number
USHORT Intensity ; // Intensity value
} ScanPnt ;

http://www.scribd.com/doc/88768096/282/Ter...an-binary-files
PM MAIL   Вверх
Freimaks
Дата 14.4.2012, 16:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Я инфу беру тоже из мануала к TerraScan-y.
Ту портянку с кучей параметров, их обязательностью и т.п. я взял от туда же.
Я попробую у одного программера выудить инфу о том как он читает эти файлы - там помоему как-то через сишные библиотеки делается.
Просто че-то это какая-то морока.
Просто почти весь софт для этой отрасли пишется на С++, поэтому для Delphi приходится изобретать колесо.
Если будет инфа и решения - я обязательно напишу, дабы не потерялось - может кому пригодится.

Сама точка в этом формате, действительно может иметь только обязательные параметры, но есть еще куча необязательных - софт их должен воспринимать если они есть.

Это сообщение отредактировал(а) Freimaks - 14.4.2012, 16:05
PM MAIL   Вверх
Freimaks
Дата 16.4.2012, 13:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Немного поколдовав получилось считать инфу по точкам:
1. Описание 2-х типов:
Код

var BinPoints_20020715 : packed record
PointCoordX: integer;
PointCoordY: integer;
PointCoordZ: integer;
PointCode: byte;
PointEcho: byte;
PointFlag: byte;
PointMark: byte;
PointLine: word;
PointInt:  word;
PointTime: cardinal;
end;
var BinPoints_20010712 : packed record
PointCode: byte;
PointLine: byte;
PointEcho: word;
PointInt:  word;
PointCoordX: integer;
PointCoordY: integer;
PointCoordZ: integer;
end;

В принципе надо будет еще расширить, так как опционально пишется еще цвет ТЛС.
Процедуры без изменений:
Код

procedure ReadBinHeaderWithRecord(const FileName: String);
begin
    with TBinaryReader.Create(FileName) do
  try
    BaseStream.Read(BinHeader, SizeOf(BinHeader));
  finally
    Free;
end;
end;


procedure ReadBinPointsWithRecord(const FileName: String; Output: TStrings);
begin
    with TBinaryReader.Create(FileName) do
  try
    BaseStream.Read(BinHeader, SizeOf(BinHeader));
    begin
    while basestream.Position<>basestream.Size do
    begin
    if BinHeader.HdrVersion=20020715 then
    begin
    BaseStream.Read(BinPoints_20020715, SizeOf(BinPoints_20020715));
Output.Append(Format('CoordX: %.2n',[(BinPoints_20020715.PointCoordX-BinHeader.OrgX)/BinHeader.Units])+#13);
Output.Append(Format('PointY %.2n',[(BinPoints_20020715.PointCoordY-BinHeader.OrgY)/BinHeader.Units])+#13);
Output.Append(Format('PointZ %.2n',[(BinPoints_20020715.PointCoordZ-BinHeader.OrgZ)/BinHeader.Units])+#13);
Output.Append('Code '+inttostr(BinPoints_20020715.PointCode)+#13);
Output.Append('Echo '+inttostr(BinPoints_20020715.PointEcho)+#13);
Output.Append('Flag '+inttostr(BinPoints_20020715.PointFlag)+#13);
Output.Append('Line '+inttostr(BinPoints_20020715.PointLine)+#13);
Output.Append('Int '+inttostr(BinPoints_20020715.PointInt)+#13);
Output.Append(Format('Time %.6n',[BinPoints_20020715.PointTime*0.0002])+#13);
    end
    else
    BaseStream.Read(BinPoints_20010712, SizeOf(BinPoints_20010712));
    end;
    end;
  finally
    Free;
end;
end;


Все читается без проблем.

Теперь осталось все это засунуть в TDicrionary
PM MAIL   Вверх
Freimaks
Дата 16.4.2012, 16:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Цитата(Qu1nt @  13.4.2012,  11:37 Найти цитируемый пост)
Dementor, используй TDictionary из Generics.Collections. 

А не могли бы привести пример как это сделать???
Посмотрев вот на это http://docwiki.embarcadero.com/CodeSamples...ionary_(Delphi) я так и не понял как мне мои точки засунуть в эту таблицу.
И сразу задам еще вопрос - как инструмент поступает с одинаковыми значениями?
Т.е. по идеи не хотелось бы, чтобы он сразу удалял дубли...

Попробовал вот так:
Код

var
i:integer;
  Dictionary: TDictionary<integer, integer>;

Далее в процедуре:
Код

procedure ReadBinPointsWithRecord(const FileName: String; Output: TStrings);
begin
i:=1;
    with TBinaryReader.Create(FileName) do
  try
    BaseStream.Read(BinHeader, SizeOf(BinHeader));
    begin
    while basestream.Position<>basestream.Size do
    begin
if (BinHeader.HdrVersion=20020715) then  //проверяем версию файла, если 20020715, то
    begin
    if (BinHeader.Time>0) and (BinHeader.Color=0) then //есть время, нет цвета
    begin
BaseStream.Read(BinPoints_20020715_time, SizeOf(BinPoints_20020715_time));
Dictionary.Add(i,BinPoints_20020715_time.PointCoordX);
i:=i+1;
..................................

Выдает ошибку Access violation at address....

Это сообщение отредактировал(а) Freimaks - 16.4.2012, 16:48
PM MAIL   Вверх
Qu1nt
Дата 16.4.2012, 17:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Цитата(Freimaks @  16.4.2012,  15:35 Найти цитируемый пост)
Т.е. по идеи не хотелось бы, чтобы он сразу удалял дубли...

А какое поведение тебе нужно?
Цитата(Freimaks @  16.4.2012,  15:35 Найти цитируемый пост)
Выдает ошибку Access violation at address....

Прежде чем работать с объектом, его нужно создать. И не забыть уничтожить.

PM MAIL   Вверх
Freimaks
Дата 16.4.2012, 17:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Цитата(Qu1nt @  16.4.2012,  15:15 Найти цитируемый пост)
А какое поведение тебе нужно?

Я рассматриваю несколько вариантов работы программы:
1. Анализ данных на наличие дублей, при этом пользователь получает отчет типа да\нет
2. Поиск дублей по всем точкам и действия над дублями (удаление или изменение параметра класс)
3. Поиск дублей для точек в определенных классах

Цитата(Qu1nt @  16.4.2012,  15:15 Найти цитируемый пост)
Прежде чем работать с объектом, его нужно создать. И не забыть уничтожить.

А как это сделать? Я просто в этом уже не разбираюсь вообще.
В Uses я добавил Generics.Collections и больше ничего не изменял
PM MAIL   Вверх
Freimaks
Дата 17.4.2012, 12:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Как я понимаю хэш-таблицы, в том числе и TDictionary, не позволяют хранить дубликаты.
А насколько логично использовать массив в данном случае???
PM MAIL   Вверх
Qu1nt
Дата 17.4.2012, 13:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Да, можно использовать шаблонный TList.
PM MAIL   Вверх
Freimaks
Дата 17.4.2012, 14:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Да, я его и взял.
Делаю так:
1. Объявляю класс
Код

TPoint = class
    private
      // Поля данных
      PointCoordX : Integer;
      PointCoordY : Integer;
      PointCoordZ : Integer;
      PointCode: byte;
      PointEcho: byte;
      PointFlag: byte;
      PointMark: byte;
      PointLine: word;
      PointInt:  word;
      PointTime: cardinal;
    public
      // Свойства для чтения значений данных
      property CoordX : Integer
          read PointCoordX;
      property CoordY : Integer
          read PointCoordY;
      property CoordZ : Integer
          read PointCoordZ;
      property Code : byte
          read PointCode;
      property Echo : byte
          read PointEcho;
      property Flag : byte
          read PointFlag;
      property Mark : byte
          read PointMark;
      property Line : word
          read PointLine;
      property Int : word
          read PointInt;
      property Time : cardinal
          read PointTime;

      // Коструктор
      constructor Create(
      const      PointCoordX : Integer;
      const      PointCoordY : Integer;
      const      PointCoordZ : Integer;
      const      PointCode: byte;
      const      PointEcho: byte;
      const      PointFlag: byte;
      const      PointMark: byte;
      const      PointLine: word;
      const      PointInt:  word;
      const      PointTime: cardinal);
  end;

2. Далее описываю Конструктор для класса Point
Код

// Конструктор Point
constructor TPoint.Create(
      const      PointCoordX : Integer;
      const      PointCoordY : Integer;
      const      PointCoordZ : Integer;
      const      PointCode: byte;
      const      PointEcho: byte;
      const      PointFlag: byte;
      const      PointMark: byte;
      const      PointLine: word;
      const      PointInt:  word;
      const      PointTime: cardinal);
begin
  // Сохранение переданных параметров
  self.PointCoordX := PointCoordX;
  self.PointCoordY := PointCoordY;
  self.PointCoordZ := PointCoordZ;
  self.PointCode := PointCode;
  self.PointEcho := PointEcho;
  self.PointFlag := PointFlag;
  self.PointMark := PointMark;
  self.PointLine := PointLine;
  self.PointInt  := PointInt;
  self.PointTime := PointTime;
end;

3. Ну и в заключении в процедуру чтения добавил заполнение Point
Код

procedure ReadBinPointsWithRecord(const FileName: String);
var point: tpoint;
begin
DataList:=Tlist.Create;
with TBinaryReader.Create(FileName) do
try
BaseStream.Read(BinHeader, SizeOf(BinHeader));
begin
while basestream.Position<>basestream.Size do
begin
BaseStream.Read(BinPoints_20020715_time, SizeOf(BinPoints_20020715_time));
Point:=TPoint.Create(
BinPoints_20020715_time.PointCoordX,
BinPoints_20020715_time.PointCoordY,
BinPoints_20020715_time.PointCoordZ,
BinPoints_20020715_time.PointCode,
BinPoints_20020715_time.PointEcho,
BinPoints_20020715_time.PointFlag,
BinPoints_20020715_time.PointMark,
BinPoints_20020715_time.PointLine,
BinPoints_20020715_time.PointInt,
BinPoints_20020715_time.PointTime);
DataList.Add(Point);
end

Теперь буду писать обработку инфы в TList
PM MAIL   Вверх
Freimaks
Дата 18.4.2012, 07:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Вообще с TList получается как-то громоздко на мой взгляд.

Узнал такую вещь - в прогах на C++ данные закачиваются в память в виде динамического массива. Т.е. - каждая точка это структура (в делфи - record), а весь бин - это динамический массив структур.

Вопрос - как описать массив из record в моем случае???

Сделал вот так
Код

type
TBinPoints_20020715_time = packed record //стандартный bin без цвета
PointCoordX: integer;
PointCoordY: integer;
PointCoordZ: integer;
PointCode: byte;
PointEcho: byte;
PointFlag: byte;
PointMark: byte;
PointLine: word;
PointInt:  word;
PointTime: cardinal;
end;


далее в переменных прописал
Код

P20020715_t:TBinPoints_20020715_time;
 Parr1:array of TBinPoints_20020715_time;


И далее в процедуре чтения:
Код

procedure ReadBinPointsWithRecord(const FileName: String);
begin
i:=0;
with TBinaryReader.Create(FileName) do
try
BaseStream.Read(BinHeader, SizeOf(BinHeader));
SetLength(Parr1, BinHeader.PntCnt);
begin
while basestream.Position<>basestream.Size do
begin//проверяем версию файла, если 20020715, то
if (BinHeader.HdrVersion=20020715) then
begin //есть время, нет цвета
if (BinHeader.Time>0) and (BinHeader.Color=0) then
begin
BaseStream.Read(P20020715_t, SizeOf(P20020715_t));
parr1[i]:= P20020715_t;
i:=i+1;
end


Не знаю на сколько правильно, но ошибок не выдает...

Это сообщение отредактировал(а) Freimaks - 18.4.2012, 11:02
PM MAIL   Вверх
Qu1nt
Дата 18.4.2012, 13:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Я бы использовал классы. Ведь, тебе все-равно нужно будет прогонять все точки через TDictionary для поиска дубликатов. В случае с классами будет копироваться только указатель, иначе — объект.
PM MAIL   Вверх
Freimaks
Дата 18.4.2012, 13:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Цитата(Qu1nt @  18.4.2012,  11:30 Найти цитируемый пост)
Я бы использовал классы. Ведь, тебе все-равно нужно будет прогонять все точки через TDictionary для поиска дубликатов. В случае с классами будет копироваться только указатель, иначе — объект. 

И еще - как установить этот компонент??? Я всегда работал только со встроенными компонентами и об установке сторонних никогда не слышал.
Щас читаю http://docs.embarcadero.com/products/rad_s...collections.pdf
Пока мало что понятно

Это сообщение отредактировал(а) Freimaks - 18.4.2012, 14:42
PM MAIL   Вверх
Qu1nt
Дата 18.4.2012, 14:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Вечером. После работы и до футбола smile

@ Добавлено
TDictionary — стандартный компонент начиная c Delphi 2009. Я надеюсь у тебя не Delphi 7?

Это сообщение отредактировал(а) Qu1nt - 18.4.2012, 14:46
PM MAIL   Вверх
Freimaks
Дата 18.4.2012, 14:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Если честно, то у меня установлено Delphi XE2...
PM MAIL   Вверх
Qu1nt
Дата 18.4.2012, 14:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Отлично. Это самая последняя версия на данный момент. Для того, чтобы его использовать достаточно подключить соответствующий модуль.
PM MAIL   Вверх
Freimaks
Дата 18.4.2012, 14:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



А, все завелось!!! Я просто не туда прописал   Dictionary:TDictionary<Integer, Integer>; поэтому и не пахало!!!
А я уже начал гугл рыть на предмет установки этой примочки...
PM MAIL   Вверх
Freimaks
Дата 18.4.2012, 15:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Ну в общем вот пока что смог сделать с этим TDictionary:
Код

var
Dictionary:TDictionary<integer, TBinPoints_time>;
------------------------------------------------------------------
begin
i:=0;
Dictionary.Destroy;
Dictionary := TDictionary<integer, TBinPoints_time>.Create;
with TBinaryReader.Create(FileName) do
try
BaseStream.Read(BinHeader, SizeOf(BinHeader));
SetLength(PTimeArray, BinHeader.PntCnt); - удалю
SetLength(PTimeColorArray, BinHeader.PntCnt); - удалю
SetLength(PLiteArray, BinHeader.PntCnt); - удалю
while basestream.Position<>basestream.Size do
begin
if (BinHeader.Time>0) and (BinHeader.Color=0) then
begin
BaseStream.Read(PTime, SizeOf(PTime));
Dictionary.Add(i,PTime);
i:=i+1;

Потом просто проверил работает ли
Код

Showmessage(inttostr(dictionary.Count));

Выводит нужное число, т.е. скока было в файле. Все супер. Разбираюсь дальше.

Добавлено через 6 минут и 26 секунд
Прав ли я считая, что Key в Dictionary.Add и есть тот самый уникальный ключ, который показывает есть такая запись или нет?
Если да, то как мне этот ключ получить? Наверно нужно в качестве ключа использовать что-то типа суммы MD5???
Если то что написал - бред, не пинайте! Пока только это пришло в голову...
PM MAIL   Вверх
Freimaks
Дата 18.4.2012, 18:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Сделал как и советовали классами (пока только один завел, тестовый). И перестало работать.
Вот чего делаю:
Завожу класс
Код

type
TBinPoints_time = class(TObject)
private
PointCoordX: integer;
PointCoordY: integer;
PointCoordZ: integer;
PointCode: byte;
PointEcho: byte;
PointFlag: byte;
PointMark: byte;
PointLine: word;
PointInt:  word;
PointTime: cardinal;
public
property CoordX : Integer
read PointCoordX;
property CoordY : Integer
read PointCoordY;
property CoordZ : Integer
read PointCoordZ;
property Code : byte
read PointCode;
property Echo : byte
read PointEcho;
property Flag : byte
read PointFlag;
property Mark : byte
read PointMark;
property Line : word
read PointLine;
property Int : word
read PointInt;
property Time : cardinal
read PointTime;

constructor Create(
      const      PointCoordX : Integer;
      const      PointCoordY : Integer;
      const      PointCoordZ : Integer;
      const      PointCode: byte;
      const      PointEcho: byte;
      const      PointFlag: byte;
      const      PointMark: byte;
      const      PointLine: word;
      const      PointInt:  word;
      const      PointTime: cardinal);
end;

Делаю конструктор:
Код

constructor TBinPoints_time.Create(
      const      PointCoordX : Integer;
      const      PointCoordY : Integer;
      const      PointCoordZ : Integer;
      const      PointCode: byte;
      const      PointEcho: byte;
      const      PointFlag: byte;
      const      PointMark: byte;
      const      PointLine: word;
      const      PointInt:  word;
      const      PointTime: cardinal);
      begin
  self.PointCoordX := PointCoordX;
  self.PointCoordY := PointCoordY;
  self.PointCoordZ := PointCoordZ;
  self.PointCode := PointCode;
  self.PointEcho := PointEcho;
  self.PointFlag := PointFlag;
  self.PointMark := PointMark;
  self.PointLine := PointLine;
  self.PointInt  := PointInt;
  self.PointTime  := PointTime;
end;

В переменных добавляю новое значение
Код

PointTime: TBinPoints_time;
Dictionary:TDictionary<integer, TBinPoints_time>;

Ну и собственно процедура чтения:
Код

procedure ReadBinPointsWithRecord(const FileName: String);
begin
i:=0;
Dictionary := TDictionary<integer, TBinPoints_time>.Create;
with TBinaryReader.Create(FileName) do
try
BaseStream.Read(BinHeader, SizeOf(BinHeader));
while basestream.Position<>basestream.Size do
begin
if (BinHeader.Time>0) and (BinHeader.Color=0) then
begin
BaseStream.Read(PointTime, SizeOf(TBinPoints_time));
PointTime:=TBinPoints_time.Create(
PointTime.PointCoordX,
PointTime.PointCoordY,
PointTime.PointCoordZ,
PointTime.PointCode,
PointTime.PointEcho,
PointTime.PointFlag,
PointTime.PointMark,
PointTime.PointLine,
PointTime.PointInt,
PointTime.PointTime);
Dictionary.AddOrSetValue(i, PointTime);
i:=i+1;
end
else
if (BinHeader.Time>0) and (BinHeader.Color>0) then
begin
BaseStream.Read(BinPoints_time_color, SizeOf(BinPoints_time_color));
end
else
begin
BaseStream.Read(BinPoints_Lite, SizeOf(BinPoints_Lite));
end;
end;
finally
Free;
end;
Showmessage(inttostr(dictionary.Count));
BinHeader.PntCnt:=Dictionary.Count;
Dictionary.Destroy;
end;


В итоге при считывании выдает ошибку Access violation at address 0053c49d in module...
PM MAIL   Вверх
Freimaks
Дата 18.4.2012, 18:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Заменил TBinPoints_time = class(TObject) на TBinPoints_time = packed record и все заработало
PM MAIL   Вверх
Freimaks
Дата 18.4.2012, 19:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Появился еще один вопрос. А как после загрузки в TDictionary вернуть все ее содержимое? Т.е. мне же потом надо все переписать в новый файл.
Процедуру записи я написал, но как достать то, что лежит в TDictionary я так и не понял (отдельными полями я понял как достать).
Т.е. что надо указывать в записи BaseStream.Write(???????????????, SizeOf(TBinPoints_time));


Сделал вот так, на сколько правильно я не знаю, но работает
Код

procedure WriteBinPointsWithRecord(const FileName: String);
begin
with TBinaryWriter.Create(FileName) do
try
BaseStream.Write(BinHeader, SizeOf(BinHeader));
for i := 0 to Binheader.PntCnt-1 do
begin
PointTime:=TBinPoints_time.Create(
Dictionary.Items[i].PointCoordX,
Dictionary.Items[i].PointCoordY,
Dictionary.Items[i].PointCoordZ,
Dictionary.Items[i].PointCode,
Dictionary.Items[i].PointEcho,
Dictionary.Items[i].PointFlag,
Dictionary.Items[i].PointMark,
Dictionary.Items[i].PointLine,
Dictionary.Items[i].PointInt,
Dictionary.Items[i].PointTime);
BaseStream.Write(PointTime, SizeOf(TBinPoints_time));
end;
finally
Free;
end;
Dictionary.Destroy;
end;


Это сообщение отредактировал(а) Freimaks - 18.4.2012, 19:54
PM MAIL   Вверх
Qu1nt
Дата 18.4.2012, 21:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Ты не понимаешь разницы между record, packed record и class. Лучше чем в книге я тебе не объясню.

PM MAIL   Вверх
Freimaks
Дата 18.4.2012, 21:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Да, в теории я не силен - буду читать щас
PM MAIL   Вверх
Freimaks
Дата 19.4.2012, 11:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Ну вроде прочитал, не могу сказать что понял 100% все, но кое что прояснилось в моей голове.
Завел один класс TBinPoints, в качестве полей класса описал все возможные поля записи в bin-файле, определил их свойства и сделал три конструктора (по одному для каждого из типов файлов).
Далее как понял мне все-равно надо использовать записи, чтобы считывать файл. Завел соответственно 3 записи, которые использую для BaseStream.Read(Запись, SizeOf(запись)).
Вроде все правильно, да и все работает.
Я не могу понять теперь, что мне использовать в качестве Key в TDictionary. Ради интереса я делал так: 
Код

TDictionary<integer, TBinPoints>.Create;

И далее в качестве Key использовал BinPoints.PointCode (типа класс) и в итоге у меня в TDictionary оставалось количество записей=количеству разных классов.
Потом в качестве Key попробовал указывать MD5 от строки из координат... работает конечно - но долго до невозможности.
В общем пока остались вопросы по Key в TDictionary.
PM MAIL   Вверх
Qu1nt
Дата 19.4.2012, 23:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Читай про устройство хеш-таблиц. Вот, один из простеньких вариантов:
Код

type
  TPoint = class
    X: Integer;
    Y: Integer;
    Z: Integer;
    constructor Create(const X, Y, Z: Integer);
  end;

  TPointComparer = class(TEqualityComparer<TPoint>)
    function Equals(const Left, Right: TPoint): Boolean; override;
    function GetHashCode(const Value: TPoint): Integer; override;
  end;

  TPointSolver = class
    Points: TList<TPoint>;
    constructor Create(const Points: TList<TPoint>);
    procedure DeleteDuplicates(const Comparer: IEqualityComparer<TPoint>);
    procedure PrintPoints(const Output: TStrings; const Details: String = '');
  end;

constructor TPoint.Create(const X, Y, Z: Integer);
begin
  Self.X := X;
  Self.Y := Y;
  Self.Z := Z;
end;

function TPointComparer.Equals(const Left, Right: TPoint): Boolean;
begin
  Result := (Left.X = Right.X) and (Left.Y = Right.Y) and (Left.Z = Right.Z);
end;

function TPointComparer.GetHashCode(const Value: TPoint): Integer;
begin
  Result := 17;
  Result := Result * 23 + Value.X;
  Result := Result * 23 + Value.Y;
  Result := Result * 23 + Value.Z;
end;

constructor TPointSolver.Create(const Points: TList<TPoint>);
begin
  Self.Points := Points;
end;

procedure TPointSolver.DeleteDuplicates(const Comparer: IEqualityComparer<TPoint>);
var
  Dictionary: TDictionary<TPoint, Integer>;
  I: Integer;
begin
  Dictionary := TDictionary<TPoint, Integer>.Create(Comparer);
  try
    for I := Points.Count - 1 downto 0 do
      if Dictionary.ContainsKey(Points[I]) then
        Points.Delete(I)
      else
        Dictionary.Add(Points[I], 0);
  finally
    Dictionary.Free;
  end;
end;

procedure TPointSolver.PrintPoints(const Output: TStrings; const Details: String = '');
var
  Point: TPoint;
begin
  Output.Append(Details);
  for Point in Points do
  begin
    Output.Append(Format('X: %d Y: %d Z: %d', [Point.X, Point.Y, Point.Z]));
  end;
end;

procedure TestPointSolver(const Output: TStrings);
var
  Points: TList<TPoint>;
begin
  Points := TObjectList<TPoint>.Create();
  try
    Points.AddRange([TPoint.Create(0, 0, 0), TPoint.Create(0, 0, 1),
      TPoint.Create(0, 1, 0), TPoint.Create(0, 0, 0), TPoint.Create(0, 0, 1)]);
    with TPointSolver.Create(Points) do
    try
      PrintPoints(Output, 'Before delete duplicates:');
      DeleteDuplicates(TPointComparer.Create);
      PrintPoints(Output, 'After delete duplicates:');
    finally
      Free;
    end;
  finally
    Points.Free;
  end;
end;

PM MAIL   Вверх
Freimaks
Дата 20.4.2012, 07:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Решил проблему с ключом несколько иначе: создал запись из пяти полей (X,Y,Z,Time,Code) и в качестве ключа использую эту запись в соответствии с требованиями подхода - либо только 4 поля, либо все 5. Вроде работает, дубли ищет.
В примере как я понял ключ генерится с помощью function TPointComparer.GetHashCode(const Value: TPoint): Integer;.
Как работают хеш-таблицы я почитал - я хотел примерно такое же сделать ручками на базе двух массивов, но так как потом получилось завести Dictionary, то решил на это забить.
В принципе то, что я сваял на данный момент работает, но не идеально.

PM MAIL   Вверх
Qu1nt
Дата 20.4.2012, 09:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



К сожалению, стандартного шаблонного множества в Delphi нет, как и аналога С++ std::multimap. Поэтому для экономии памяти я бы использовал в TDictionary только поле ключа. И в зависимости от задачи менял только компаратор.
PM MAIL   Вверх
Freimaks
Дата 20.4.2012, 12:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Цитата(Qu1nt @  20.4.2012,  07:30 Найти цитируемый пост)
Поэтому для экономии памяти я бы использовал в TDictionary только поле ключа. И в зависимости от задачи менял только компаратор. 

Да, это актуально, т.к. памяти все это жрет не мало.
Но больше всего меня беспокоит скорость чтения\записи. Я думал, что торможение идет в следствии различных операций переброса значений в класс, в запись в Dictionary.
Но это влияет в меньшей степени.
Сделал отдельную процедуру просто для чтения одного файла.
Код

procedure TForm1.Button2Click(Sender: TObject);
var g:integer;
begin
g:=1;
with TBinaryReader.Create('d:\data\2332371--.bin') do
try
BaseStream.Read(BinHeader, SizeOf(BinHeader));
ProgressBar1.Min:=1;
ProgressBar1.Max:=BinHeader.PntCnt;
while basestream.Position<>basestream.Size do
begin
Application.ProcessMessages;
BaseStream.Read(RPointsTime, SizeOf(RPointsTime));
ProgressBar1.Position:=g;
g:=g+1;
end;
finally
  Free;
end;
end;

Чтение этого файла размеров в 53.3 мегабайта занимает около 30 секунд... если не больше.
Можно как-то ускорить. Хотя бы куда копать не подскажете?
PM MAIL   Вверх
Qu1nt
Дата 20.4.2012, 12:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Как ситуация меняется, если убрать взаимодействие с пользовательским интерфейсом? Убери Application.ProcessMessages и ProgressBar из цикла.
PM MAIL   Вверх
Freimaks
Дата 20.4.2012, 13:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Сократил до минимума... толку никакого. Я просто понять не могу в чем проблема - т.е. я что-то делаю не так, инструмент медленный или что вообще не так. В родной проге этот файл открывается за 1-2 секунды...
Код

procedure TForm1.Button2Click(Sender: TObject);
begin
with TBinaryReader.Create('d:\OPTEN\TPMAK\data\With_thinpoint_2332371--.bin') do
try
BaseStream.Read(BinHeader, SizeOf(BinHeader));
while basestream.Position<>basestream.Size do
BaseStream.Read(RPointsTime, SizeOf(RPointsTime));
ShowMessage('Готово');
finally
Free;
end;
end;

RPointsTime - это packed record.
PM MAIL   Вверх
Qu1nt
Дата 20.4.2012, 13:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Хорошо, в таком случае нужно читать блочно. Попробуй за раз читать несколько тысяч точек. 
PM MAIL   Вверх
Freimaks
Дата 20.4.2012, 13:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Цитата(Qu1nt @  20.4.2012,  11:39 Найти цитируемый пост)
Хорошо, в таком случае нужно читать блочно. Попробуй за раз читать несколько тысяч точек.  

А не подскажите, как это сделать???
PM MAIL   Вверх
Freimaks
Дата 20.4.2012, 15:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Я понял как делать!!! Ща усе сделаю smile
PM MAIL   Вверх
Qu1nt
Дата 20.4.2012, 22:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Только добрался до компилятора. Ага, оказывается свойства Position и Size не кэшируются, отсюда такое проседание. Добавив буфер и исправив этот момент получил значительный прирост в производительности. Загрузка 200 МБ файла в список у меня занимает меньше секунды.
Код

procedure ReadWithBuffer(const FileName: String);
const
  MAX_BUFFER_SIZE = 10000;
var
  PointsBuffer: array of TPackedPoint;
  Points: TList<TPoint>;
  TotalCount, Count, I: Integer;
begin
  Points := TObjectList<TPoint>.Create;
  try
    with TBinaryReader.Create(FileName) do
    try
      TotalCount := ReadInteger;
      SetLength(PointsBuffer, Min(TotalCount, MAX_BUFFER_SIZE));
      Points.Capacity := TotalCount;
      while TotalCount > 0 do
      begin
        Count := Min(TotalCount, Length(PointsBuffer));
        BaseStream.ReadBuffer(PointsBuffer[0], SizeOf(PointsBuffer[0]) * Count);
        Dec(TotalCount, Count);
        for I := 0 to Count - 1 do
          Points.Add(TPoint.Create(PointsBuffer[I].X, PointsBuffer[I].Y, PointsBuffer[I].Z));
      end;
    finally
      Free;
    end;
  finally
    Points.Free;
  end;
end;


Это сообщение отредактировал(а) Qu1nt - 20.4.2012, 22:22
PM MAIL   Вверх
Freimaks
Дата 21.4.2012, 07:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Да, я сначала пытался просто Position и Size определять до входа в цикл чтения файла - прирост был.
Но больше всего помогло чтение файла за один раз, а потом циклом раскидывание его в Dictionary.
Выглядит вот так (кусок кода):
Код

procedure ReadBinPointsWithRecord(const FileName: String);
var i:integer; Pair:Tpair;
begin
Dictionary := TDictionary<TPair,TBinPoints>.Create;
with TBinaryReader.Create(FileName) do
try
BaseStream.Read(BinHeader, SizeOf(BinHeader));
OldPointCount:=BinHeader.PntCnt;
if (BinHeader.Time>0) and (BinHeader.Color=0) then
begin
SetLength(RPointsTimeArray,BinHeader.PntCnt); //задаем длину массива (RPointsTimeArray array of RPointsTime), равную количеству точек
BaseStream.Read(RPointsTimeArray[0], BinHeader.PntCnt*SizeOf(TRPointsTime)); //читаем файл за один раз
for i := 0 to BinHeader.PntCnt-1 do
begin
BinPoints:=TBinPoints.Create(
RPointsTimeArray[i].PointCoordX,
RPointsTimeArray[i].PointCoordY,
RPointsTimeArray[i].PointCoordZ,
RPointsTimeArray[i].PointCode,
RPointsTimeArray[i].PointEcho,
RPointsTimeArray[i].PointFlag,
RPointsTimeArray[i].PointMark,
RPointsTimeArray[i].PointLine,
RPointsTimeArray[i].PointInt,
RPointsTimeArray[i].PointTime);
if (Form1.RadioGroup1.ItemIndex=0) or (Form1.RadioGroup1.ItemIndex=1)  then
begin
Pair.PointCoordX:=BinPoints.PointCoordX;
Pair.PointCoordY:=BinPoints.PointCoordY;
Pair.PointCoordZ:=BinPoints.PointCoordZ;
Pair.PointTime:=BinPoints.PointTime;
end
else
if Form1.RadioGroup1.ItemIndex=2 then
begin
Pair.PointCoordX:=BinPoints.PointCoordX;
Pair.PointCoordY:=BinPoints.PointCoordY;
Pair.PointCoordZ:=BinPoints.PointCoordZ;
Pair.PointTime:=BinPoints.PointTime;
Pair.PointCode:=BinPoints.PointCode;
end;
Dictionary.AddOrSetValue(Pair, BinPoints);
end;
RPointsTimeArray:=nil;
end

Чтение происходит очень быстро - гораздо меньше секунды. Обработка тоже быстро проходит, запись... ну тут еще не сравнивал, пока не до нее - главное пишет правильно.
Пока не могу избавиться от двух проблем:
1. Жрет много памяти - это и логично, сначала файл в оперативку, потом дублируем его в Dictionary так еще и с ключем, состоящим из львиной доли файла. Обойти большой ключ проблематично. Но Вы говорили, что можно в качестве значений давать не сами значений класса, а лишь указатель на него. Как это сделать и как происходит удаление самих данных класса, я вообще понять не могу...
2. После отработки каждого файла в оперативке остается большое количество данных. И это не смотря на то, что я делаю обнуление массива RPointsTimeArray:=nil;, так еще и в конце обработки каждого файла делаю Dictionary.Free.
Статистика такая: подаем файл 120Мб, в оперативке максимальное потребление за время обработки примерно 550Мб, после завершения обработки остается 212Мб. Обработка (без записи) занимает время в в среднем 4200 мсек.
PM MAIL   Вверх
Qu1nt
Дата 21.4.2012, 10:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



В общем я не знаю, что тебе сказать. Я говорю как нужно делать, привожу примеры, а ты пишешь по своему.
Подведем итог.
Не нужно весь файл в память грузить. Если бы ты запустил мой пример, увидел бы, что ~10 000 оптимальный размер буфера и его увеличение прироста не дает.
Не нужно использовать поле значения в TDictionary. Это отнимает лишнюю память.
Нужно понять разницу между TList/TObjectList, TDictionary/TObjectDictionary.
Нужно научиться форматировать код.
Нужно избавиться от глобальных переменных в пользу ООП.
PM MAIL   Вверх
Freimaks
Дата 21.4.2012, 10:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Попробую переделать. Буду учить матчасть...
PM MAIL   Вверх
Freimaks
Дата 27.4.2012, 10:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Все сделал как советовали - действительно так лучше. Пробовал с разным размером буфера при считывании - да, после 10000 прироста нет (если и есть то он незначительный).
Переделал таким же макаром и запись, единственное при записи я использую буфер большего размера - 1 000 000 записей, дальше прироста нет, меньше - скорость записи падает.
Вроде бы щас написал все алгоритмы (сделал даже переброс точек в другой класс при нахождении дубликатов).
Все работает, но есть одно но, исправить которое наверно и невозможно. Это скорость самой обработки.
Сейчас у меня такой расклад: файл 240 Мб., 10506680 точек (все сдвоенные). Обработка от начала и до конца занимает 27815 мсек, из которых на саму обработку (удаление дубликатов) уходит 11482 мсек. Остальное сжирается записью и чтением.
Примерное сравнение с аналогичной программой - мое творение работает раз в 10 медленнее.
PM MAIL   Вверх
Qu1nt
Дата 27.4.2012, 11:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Показывай весь проект.
PM MAIL   Вверх
Freimaks
Дата 27.4.2012, 11:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Сразу извиняюсь если что-то написано не грамотно, но я так сказать пока только учусь.
Выкладываю процедуры чтения и записи (все остальное это просто обращение к ним и в зависимости от результата формирование отчетов и т.п.
Процедура чтения (всего три варианта, т.к. три вида файлов):
Код

procedure ReadBinPointsWithRecord(const FileName: String);
const MAX_BUFFER_SIZE = 10000;
var i, totalcount, count:integer;
begin
Diff1:=0;
g:=0;
Dictionary := TObjectDictionary<string,integer>.Create;
with TBinaryReader.Create(FileName) do
try
BaseStream.Read(BinHeader, SizeOf(BinHeader));
OldPointCount:=BinHeader.PntCnt;
TotalCount:=BinHeader.PntCnt;
if (BinHeader.Time>0) and (BinHeader.Color=0) then
begin
  List1:=TList<TRpointsTime>.Create;
  SetLength(RPointsTimeArray, Min(TotalCount,MAX_BUFFER_SIZE));
  List1.Capacity:=TotalCount;
  while TotalCount > 0 do
    begin
    Count := Min(TotalCount, Length(RPointsTimeArray));
    BaseStream.Read(RPointsTimeArray[0], Count*SizeOf(TRPointsTime));
    Dec(TotalCount, Count);
      for i := 0 to Count-1 do
        begin
        Start1 := GetTickCount();
        Keymachen(RPointsTimeArray[i].PointCoordX, RPointsTimeArray[i].PointCoordy,
        RPointsTimeArray[i].PointCoordz, RPointsTimeArray[i].PointTime,RPointsTimeArray[i].PointCode);
        if Dictionary.ContainsKey(key)=false then
        begin
        List1.Add(RPointsTimeArray[i]);
        Dictionary.Add(key, 0);
        End1 := GetTickCount();
        Diff1 := Diff1+(End1 - Start1);
        end
        else
          begin
          if Form1.RadioGroup2.ItemIndex=1 then
          Begin
            RPointsTimeArray[i].PointCode:=strtoint(Form1.LabeledEdit1.Text);
            List1.Add(RPointsTimeArray[i]);
            Inc(g);
          End;
          end;
      end;
end;
RPointsTimeArray:=nil;
SetLength(RPointsTimeArray,0);
end
else
if (BinHeader.Time>0) and (BinHeader.Color>0) then
begin
  List2:=TList<TRpointsTimeColor>.Create;
  SetLength(RPointsTimeColorArray, Min(TotalCount,MAX_BUFFER_SIZE));
  List2.Capacity:=TotalCount;
  while TotalCount > 0 do
    begin
    Count := Min(TotalCount, Length(RPointsTimeColorArray));
    BaseStream.Read(RPointsTimeColorArray[0], Count*SizeOf(TRPointsTimeColor));
    Dec(TotalCount, Count);
      for i := 0 to Count-1 do
        begin
        Keymachen(RPointsTimeColorArray[i].PointCoordX, RPointsTimeColorArray[i].PointCoordy,
        RPointsTimeColorArray[i].PointCoordz, RPointsTimeColorArray[i].PointTime,RPointsTimeColorArray[i].PointCode);
        if Dictionary.ContainsKey(key)=false then
        begin
        List2.Add(RPointsTimeColorArray[i]);
        Dictionary.Add(key, 0);
        end
        else
          begin
          if Form1.RadioGroup2.ItemIndex=1 then
          Begin
            RPointsTimeColorArray[i].PointCode:=strtoint(Form1.LabeledEdit1.Text);
            List2.Add(RPointsTimeColorArray[i]);
            Inc(g);
          End;
          end;
      end;
end;
RPointsTimeColorArray:=nil;
SetLength(RPointsTimeColorArray,0);
end
else
begin
  List3:=TList<TRpointsLite>.Create;
  SetLength(RPointsLiteArray, Min(TotalCount,MAX_BUFFER_SIZE));
  List3.Capacity:=TotalCount;
  while TotalCount > 0 do
    begin
    Count := Min(TotalCount, Length(RPointsLiteArray));
    BaseStream.Read(RPointsLiteArray[0], Count*SizeOf(TRPointsLite));
    Dec(TotalCount, Count);
      for i := 0 to Count-1 do
        begin
        Keymachen(RPointsLiteArray[i].PointCoordX, RPointsLiteArray[i].PointCoordy,
        RPointsLiteArray[i].PointCoordz, 0, RPointsLiteArray[i].PointCode);
        if Dictionary.ContainsKey(key)=false then
        begin
        List3.Add(RPointsLiteArray[i]);
        Dictionary.Add(key, 0);
        end
        else
          begin
          if Form1.RadioGroup2.ItemIndex=1 then
          Begin
            RPointsLiteArray[i].PointCode:=strtoint(Form1.LabeledEdit1.Text);
            List3.Add(RPointsLiteArray[i]);
            Inc(g);
          End;
          end;
      end;
end;
RPointsLiteArray:=nil;
SetLength(RPointsLiteArray,0);
end;
finally
Free;
end;
NewPointCount:=Dictionary.Count+g;
ThinPointFinded:=ThinPointFinded+(OldPointCount-NewPointCount)+g;
Form1.StringGrid1.Cells[1,7]:=inttostr(ThinPointFinded)+' шт.';
Dictionary.Free;
end;

2. Процедура записи
Код

procedure WriteBinPointsWithRecord(const FileName: String);
const MAX_BUFFER_SIZE = 1000000;
var  TotalCount, Count, i: Integer;
begin
with TBinaryWriter.Create(FileName) do
try
BinHeader.PntCnt:=NewPointCount;
TotalCount:=NewPointCount;
BaseStream.Write(BinHeader, SizeOf(BinHeader));
if (BinHeader.Time>0) and (BinHeader.Color=0) then
begin
SetLength(RPointsTimeArray,Min(TotalCount,MAX_BUFFER_SIZE));
while TotalCount > 0 do
begin
Count := Min(TotalCount, Length(RPointsTimeArray));
for i := 0 to Count-1 do
RPointsTimeArray[i]:=List1.Items[i];
BaseStream.Write(RPointsTimeArray[0], Count*SizeOf(TRPointsTime));
List1.DeleteRange(0, Count-1);
Dec(TotalCount, Count);
end;
List1.Free;
RPointsTimeArray:=nil;
SetLength(RPointsTimeArray,0);
end
else
if (BinHeader.Time>0) and (BinHeader.Color>0) then
begin
SetLength(RPointsTimeColorArray,Min(TotalCount,MAX_BUFFER_SIZE));
while TotalCount > 0 do
begin
Count := Min(TotalCount, Length(RPointsTimeColorArray));
for i := 0 to Count-1 do
RPointsTimeColorArray[i]:=List2.Items[i];
BaseStream.Write(RPointsTimeColorArray[0], Count*SizeOf(TRPointsTimeColor));
List2.DeleteRange(0, Count-1);
Dec(TotalCount, Count);
end;
List2.Free;
RPointsTimeColorArray:=nil;
SetLength(RPointsTimeColorArray,0);
end
else
begin
SetLength(RPointsLiteArray,Min(TotalCount,MAX_BUFFER_SIZE));
while TotalCount > 0 do
begin
Count := Min(TotalCount, Length(RPointsLiteArray));
for i := 0 to Count-1 do
RPointsLiteArray[i]:=List3.Items[i];
BaseStream.Write(RPointsLiteArray[0], Count*SizeOf(TRPointsLite));
List3.DeleteRange(0, Count-1);
Dec(TotalCount, Count);
end;
List3.Free;
RPointsLiteArray:=nil;
SetLength(RPointsLiteArray,0);
end;
finally
Free;
end;
end;

3. Процедура формирования ключа
Код

procedure Keymachen(const x,y,z,t:integer; c:byte);
begin
if (Form1.RadioGroup1.ItemIndex=0) or (Form1.RadioGroup1.ItemIndex=1)or
(Form1.RadioGroup1.ItemIndex=3) then
key:=inttostr(x)+inttostr(y)+inttostr(z)+inttostr(t)
else
key:=inttostr(x)+inttostr(y)+inttostr(z)+inttostr(t)+inttostr(c);
end;

4. Процедура когда нужно найти дубли, но оставить четко один класс. Написано очень тупо, но при других вариантах я получал всякую гадость
Код

Procedure ReadBinPointsWithParameters(Const FileName: string);
const MAX_BUFFER_SIZE = 10000;
var i, totalcount, count:integer;
begin
g:=0;
Dictionary := TObjectDictionary<string,integer>.Create;
with TBinaryReader.Create(FileName) do
try
BaseStream.Read(BinHeader, SizeOf(BinHeader));
OldPointCount:=BinHeader.PntCnt;
TotalCount:=BinHeader.PntCnt;
if (BinHeader.Time>0) and (BinHeader.Color=0) then
begin
  List1:=TList<TRpointsTime>.Create;
  SetLength(RPointsTimeArray, Min(TotalCount,MAX_BUFFER_SIZE));
  List1.Capacity:=TotalCount;
  while TotalCount > 0 do
    begin
    Count := Min(TotalCount, Length(RPointsTimeArray));
    BaseStream.Read(RPointsTimeArray[0], Count*SizeOf(TRPointsTime));
    Dec(TotalCount, Count);
      for i := 0 to Count-1 do
        begin
        if RPointsTimeArray[i].PointCode=strtoint(Form1.LabeledEdit3.Text) then
        begin
        Keymachen(RPointsTimeArray[i].PointCoordX, RPointsTimeArray[i].PointCoordy,
        RPointsTimeArray[i].PointCoordz, RPointsTimeArray[i].PointTime,RPointsTimeArray[i].PointCode);
        Dictionary.AddOrSetValue(key,0);
        List1.Add(RPointsTimeArray[i]);
        end;
        end;
    end;
    BaseStream.Seek(56, soFromBeginning);
    TotalCount:=BinHeader.PntCnt;
  while TotalCount > 0 do
    begin
    Count := Min(TotalCount, Length(RPointsTimeArray));
    BaseStream.Read(RPointsTimeArray[0], Count*SizeOf(TRPointsTime));
    Dec(TotalCount, Count);
      for i := 0 to Count-1 do
        begin
        if RPointsTimeArray[i].PointCode<>strtoint(Form1.LabeledEdit3.Text) then
        begin
        Keymachen(RPointsTimeArray[i].PointCoordX, RPointsTimeArray[i].PointCoordy,
        RPointsTimeArray[i].PointCoordz, RPointsTimeArray[i].PointTime,RPointsTimeArray[i].PointCode);
        if dictionary.ContainsKey(key)=false then
        begin
        Dictionary.AddOrSetValue(key,0);
        List1.Add(RPointsTimeArray[i]);
        end
        else
          begin
          if Form1.RadioGroup2.ItemIndex=1 then
          Begin
            RPointsTimeArray[i].PointCode:=strtoint(Form1.LabeledEdit1.Text);
            List1.Add(RPointsTimeArray[i]);
            Inc(g);
          End;
          end;
        end;
        end;
    end;
RPointsTimeArray:=nil;
SetLength(RPointsTimeArray,0);
end;
finally
Free;
end;
NewPointCount:=Dictionary.Count+g;
ThinPointFinded:=ThinPointFinded+(OldPointCount-NewPointCount);
Dictionary.Free;
end;

Вот все что получилось.
Сравнение с другой программой проводил, но это конечно глупо. Как она работает я не в курсе, могу лишь сказать что там делается некая сортировка. Памяти она потребляет гораздо меньше (видимо ключи там не хранятся).
Я на досуге пытался почитать Кнута, но дается пока с трудом...
PM MAIL   Вверх
Qu1nt
Дата 27.4.2012, 12:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Зачем тебе строковой ключ? Возьми за основу мой код.
PM MAIL   Вверх
Freimaks
Дата 27.4.2012, 16:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 31
Регистрация: 23.4.2011

Репутация: нет
Всего: нет



Да, Вы как всегда правы. Замена строкового ключа на просто числовой дает во-первых более чем трехкратное повышение производительности, так еще и позволяет уменьшить потребление памяти примерно в три раза. В итоге получается, что полное время обработки того же файла идет 9033 мсек, а именно обработка занимает 3291 мсек (круто!!!!). Но это так сказать грубо.
Я просто немного недопонимаю пример и как его применить на все 100%.
В вашем примере все организовано на классах, где сравнение идет с помощью Equals и GetHashCode (если я все правильно понял из прочтенной теории). У меня же все сформировано на записях (я если честно так и не понял преимущества использования классов).
Соответственно для формирования ключа я просто подсунул вот это:
Код

  Result := 17;
  Result := Result * 23 + Value.X;
  Result := Result * 23 + Value.Y;
  Result := Result * 23 + Value.Z;

И соответственно этот подход не дает уникального ключа для достаточно большого числа точек.
Правильно ли я понимаю, что все это будет работать только при условии использования классов и их методов Equals и GetHashCode.
В литературе встретил подобное вычисление HashCode, правда с другими простыми числами.
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Для новичков"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1582 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.