Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Файл и динамический массив


Страницы:   1 2

d3777 ©   (2006-04-05 18:07:00) 

есть текстовый файл. в нём матрица  чисел(несколько столбцов- m, и много-много строк - n). вопрос: как динамически выделить под него массив, точнее как определить размер этого массива?
для определения кол-ва стобцов делал read(F, W[m]) до конца первой строки - но это помоему не выход.
а со строками вообще не понял как. просто устанавливал с запасом. но это тоже не выход: так как кол-во строк от файла к фалу изменяется от 2 до 1048576.
заранее спасибо


Джо   (2006-04-05 23:56:00) [21]

> [19] Джо ©   (05.04.06 23:51)

Для "чистоты эксперимента" можно даже во втором варианте поставить SetLength (Bytes,I);


Джо   (2006-04-05 23:51:00) [22]

> d3777

Кстати, чтобы железным образом и окончательно убедить в пагубности постоянного изменения размера массива, вот код для оценки :)

type
 TByteArray = array of Byte;

 var
 LastTicks: Cardinal;

procedure StartTickTimer;
begin
 LastTicks := GetTickCount
end;

function TicksElapsed: Cardinal;
begin
 Result := GetTickCount - LastTicks
end;

{$O-}
procedure TForm1.Button1Click(Sender: TObject);
const
 MAX_LN = 100000000; // 100 million
var
 Bytes: TByteArray;
 I: Integer;
begin
 // Сразу задаем размер массива
 StartTickTimer;
 SetLength (Bytes,MAX_LN);
 ShowMessageFmt('Tick elapsed: %d',[TicksElapsed]);

 Bytes := nil;

 // На каждой итерации увеличиваем размер на единицу
 StartTickTimer;
 for I := 1 to MAX_LN do
   SetLength (Bytes,Length(Bytes)+1);
 ShowMessageFmt('Tick elapsed: %d',[TicksElapsed]);
end;
{$O+}


Попробуй и сразу ощутишь разницу :)
На моей машине первый вариант выполнился за 93 тика, а второй за 13375 . Т.е,почти в 150 раз дольше ;)


Юрий Зотов   (2006-04-05 23:42:00) [23]

Если узнать нельзя...

Почему нельзя? Чем плох способ [4]? Все сработает железно и точно, нет никаких проблем. И схема это не примерная, а точная, осталось лишь написать пару десятков строк простейшего кода.


d3777   (2006-04-05 23:39:00) [24]

хм..... лан
попробую оба способа с двумя файлами: один с мах колвом строк, а другой с мах/2. замеряю время обработки.

(у первого сразу виден минус - в начале скачёк объёма используемой памяти)
пробовал второй вариант, но читал поэлементно, а не строками - скорость на нуле, короче, практика покажет :)


Джо   (2006-04-05 23:36:00) [25]

> [14] d3777 ©   (05.04.06 23:34)
> ок. всем огромное спасибо
> остановлюсь я на выделении мах

Также не очень хороший подход :)


Джо   (2006-04-05 23:34:00) [26]

> [11] d3777 ©   (05.04.06 23:12)
> хм...... спорный выход считать первые сто строк и апроксимировать........
>
> можно не получить точное кол-во строк.

А почему не хочешь обдумать вариант с двух-проходной стратегией? Вот Ю. Зотов набросал примерную схему.


d3777   (2006-04-05 23:34:00) [27]

ок. всем огромное спасибо
остановлюсь я на выделении мах и корректировки после прочтения


Джо   (2006-04-05 23:32:00) [28]

> [11] d3777 ©   (05.04.06 23:12)
> будет ли в таком случае менеджер памяти
> весь этот массив иаскать или просто отрежет лишнее?

Будет. Откуда он знает, что там "лишнее"?


Джо   (2006-04-05 23:31:00) [29]

> [9] Anatoly Podgoretsky ©   (05.04.06 23:05)
> Если узнать нельзя, то можно оценить и выделить в два раза
> больше, по окончанию скорректировать.

Угу, я именно нечто такое и предлагал в [2].


d3777   (2006-04-05 23:12:00) [30]

хм...... спорный выход считать первые сто строк и апроксимировать........
можно не получить точное кол-во строк.

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


Anatoly Podgoretsky   (2006-04-05 23:06:00) [31]

Оценить можно так, прочитать первые сто строк и аппроксимировать на весь размер файла.


Anatoly Podgoretsky   (2006-04-05 23:05:00) [32]

Джо ©   (05.04.06 23:03) [8]
Если узнать нельзя, то можно оценить и выделить в два раза больше, по окончанию скорректировать.


Джо   (2006-04-05 23:03:00) [33]

В идеале, должен быть вообще один вызов SetLength, а именно, при первоначальной инициализации :) Т.е, самая лучшая стратегия: заранее узнавать размер массива.


Anatoly Podgoretsky   (2006-04-05 23:02:00) [34]

d3777 ©   (05.04.06 22:57) [5]
И через некоторое время получишь сообщение об нехватке памяти. Память надо выделить сразу под весь массив.


Джо   (2006-04-05 23:01:00) [35]

> [5] d3777 ©   (05.04.06 22:57)
> только насколько я знаю при увеличении размера массива старые
> данные остаются и поэтому можно сначала задать массив 1х1,
> прочитать первую строку до конца каждый раз увеличивая
> колво столбцов на единицу, а потом с циклом с размером колва
> столбцоов читать до конца файла каждай раз увеличивая массив
> на одну строку.

Очень плохое решение.

Память под массив выделяется сплошным непрерывным блоком. Если размер нового массива не помещается в выделенную память (хоть на 1 байт ;), то
1. Менеджер памяти начнет искать блок подходящего размера
2. Зарезервирует в нем место
3. Скопирует все данных их старого блока в новый.

Вообще, стоит взять за правило: своди к минимуму кол-во вызовов SetLength.


d3777   (2006-04-05 22:57:00) [36]

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

прокомментируйте пожалуйста


Юрий Зотов   (2006-04-05 21:11:00) [37]

> как определить размер этого массива?

1. Читаем первую строку целиком в строчную переменную S. Элементарный парсинг этой строки даст кол-во столбцов в массиве (кол-во разделителей плюс единица).

2. Присваиваем счетчику 1 и в цикле while not EoFчитаем в ту же переменную S остальные строки, каждый раз увеличивая счетчик на 1. Привыходе из цикла его значение даст кол-во строк в массиве.

3. Теперь пишем SetLength и повторно читаем файл уже в массив.


Anatoly Podgoretsky   (2006-04-05 19:45:00) [38]

С поправкой, вначале можно приблизительно оченить количество строк через размер файла, если взять средний размер числа + пробел
Кроме того нужна более подробная информация о файле, а вдруг колонки выровнены по ширине, тогда размер определяется просто и точно.


Джо   (2006-04-05 19:13:00) [39]

Ну, если структуру файла изменить нельзя, то, имхо, лучше не придумаешь, чем "выделять с запасом". Но делать это "по уму". Например, можно предложить такую стратегию: выделяем каждый раз в два раза больше, чем было выделено в предыдущий. В конце корректируем размер. Реальную стратегию нужно будет подобрать эмпирически на реальных (среднестатических, так сказать) данных.
Если это не подходит, то нужно изменять логику разбора содержимого файла. Например, вначале "пробегать" по всему файлу, подсчитывая строки и колонки. Затем выделить память под массив, и только после этого считывать значения.


Jeer   (2006-04-05 19:11:00) [40]

arX[i,j]
i - число строк текстового файла
j - число столбцов через парсинг строки по разграничителю.

arX: array of array of ..
SetLength()


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо