С .net я только начинаю знакомиться, но с сериализацией я знаком давно
по MFC. И там еще у меня возник вопрос, на который я ответа не нашел.
Предполагаю, что и здесь его нет, но все же, может, кто-то скажет
интересное.
Для понятности задачу слегка упростил. В действительности все было
намного сложнее.
Есть класс — двумерная матрица. Матрица сильно разрежена. Ее надо
сохранить, но нули сохранять не надо.
Для сохранения предлагется простейший формат
Целое N3 — число троек.
Первая тройка — i,j, value
Вторая тройка — i,j, value
И т.д.
Насколько я понимаю, здесь надо сериализоваться с написанием собственной
ISerializable.GetObjectData
и специального конструктора. Хорошо.
Проблема же вот в чем. Я не знаю N3. Я его узнаю, только когда
просканирую матрицу и подсчитаю число ненулевых элементов. А вывести его
надо сначала, иначе потом я не при десериализации не буду знать, сколько
троек читать.
(Конечно, есть вариант с записью в конец ограничителя — чего-то вроде
(0,0,0). Здесь он проходит, но, напоминаю, исходная задача была намного
сложнее. Так что этот вариант не рассматривается).
Получается, что алгоритм двухпроходной. На первом проходе находим N3, на
втором — записываем тройки.
Если бы вместо сериализации я просто в файл писал — алгоритм
однопроходной. Пропускаем в файле 4 байта для N3, записываем тройки
(одновременно считаем N3) , позиционируемся назад к позиции N3,
записываем ее.
Можно ли сделать алгоритм однопроходным при сериализации ?
Holmes wrote: > > Pavel, > > А как насчет варианта заранее иметь количество заполненных ячеек в матрице?
Согласен, в данном случае это возможно, но , напоминаю, исходная задача
была намного сложнее. Если хочешь, немного деталей. Матрица была
трехмерной, и вертикали в ней состояли из ненулевых кусков, вот эти
куски надо было и выводить, причем при выводе анализировалось, не был ли
такой же кусок (т.е того же размера и с такими же значениями) выведен
раньше в другой вертикали, и если да — он не выводился, а делалась
ссылка на его позицию в файле. Это все несколько минут занимало . Что
поделать, размер матрицы был огромный (порядка 5000*5000*200) и в ОП она
никогда целиком не хранилась.
PD>Если бы вместо сериализации я просто в файл писал — алгоритм PD>однопроходной. Пропускаем в файле 4 байта для N3, записываем тройки PD>(одновременно считаем N3) , позиционируемся назад к позиции N3, PD>записываем ее.
Как насчет во время сериализации записать все что нужно в ArrayList и сериализовать его?
Apollo13 wrote: > > Здравствуйте, Pavel Dvorkin, Вы писали: > > PD>Если бы вместо сериализации я просто в файл писал — алгоритм > PD>однопроходной. Пропускаем в файле 4 байта для N3, записываем тройки > PD>(одновременно считаем N3) , позиционируемся назад к позиции N3, > PD>записываем ее. > > Как насчет во время сериализации записать все что нужно в ArrayList и сериализовать его?
Ох нет, только не это . Там десятки, если не сотни Мб. См. пояснение
в моем ответе Holmes
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Матрица была PD>трехмерной, и вертикали в ней состояли из ненулевых кусков, вот эти PD>куски надо было и выводить, причем при выводе анализировалось, не был ли PD>такой же кусок (т.е того же размера и с такими же значениями) выведен PD>раньше в другой вертикали, и если да — он не выводился, а делалась PD>ссылка на его позицию в файле.
Мне кажется при таком расскладе самым разумным было бы сделать хэш-таблицу хранящую ссылки на элементы матрицы (индекс или еще что), так как иначе время поиска дубликата будет слишком велико. Ну, и потом серализовать эту хэш-таблицу.
PD> Это все несколько минут занимало . Что PD>поделать, размер матрицы был огромный (порядка 5000*5000*200) и в ОП она PD>никогда целиком не хранилась.
А насколько она разрежена? Может быть есть смысл эмулировать матрицу на хэш-таблице? Например, в экселе делается именно так. Правда с трехмерной прийдется повозиться, но все же.
... << RSDN@Home 1.1.4 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
VladD2 wrote: > > Здравствуйте, Pavel Dvorkin, Вы писали:
<skipped>
> А насколько она разрежена? Может быть есть смысл эмулировать матрицу на хэш-таблице? Например, в экселе делается именно так. Правда с трехмерной прийдется повозиться, но все же.
Похоже, дело свелось к обсуждению того, как лучше эту матрицу хранить и
выводить. Не это меня интересует, а другое.
Можно ли при сериализации с собственной реализацией GetObjectData
передвигаться в потоке ? Т.е. оставить место , а потом к нему вернуться
и записать значение. Например
Оставить место для A
Вывести B
Вывести C
Вывести D
Вернуться и записать A
Вернуться в позицию после D
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Похоже, дело свелось к обсуждению того, как лучше эту матрицу хранить и PD>выводить. Не это меня интересует, а другое.
Дык именно неверное представление в первую очередь бросается в глаза.
PD>Можно ли при сериализации с собственной реализацией GetObjectData PD>передвигаться в потоке ? Т.е. оставить место , а потом к нему вернуться PD>и записать значение.
Ты волен создать свой поток и делать с ним что душа пожелает. Бинари- и Соап-форматер принимают именованные значения через SerializationInfo.AddValue(). Подсунь туда свой массив байтов или стрим.
... << RSDN@Home 1.1.4 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD> ...[skipped]...
PD>Есть класс — двумерная матрица. Матрица сильно разрежена. Ее надо PD>сохранить, но нули сохранять не надо.
PD>Насколько я понимаю, здесь надо сериализоваться с написанием собственной PD>ISerializable.GetObjectData PD> и специального конструктора. Хорошо.
При сериализации в Net в поток пишешь не ты. Собственно... порядок параметров не важен.
Сделай так:
ArrayList rowsList = new ArrayList(/*~N*/);
.... // добавление троек.
int[][] rows = rowsList.ToArray(typeof(int[])) as int[][];
или
int[,] rows = ....
info.AddValue("rows", rows);
ну а N, вообще говоря, теперь и не нужно никуда писать.
VladD2 wrote: > > Здравствуйте, Pavel Dvorkin, Вы писали: > > PD>Похоже, дело свелось к обсуждению того, как лучше эту матрицу хранить и > PD>выводить. Не это меня интересует, а другое. > > Дык именно неверное представление в первую очередь бросается в глаза.
Ну и бог с ним . Я ведь не об этом спрашиваю, а о сериализации.
> > PD>Можно ли при сериализации с собственной реализацией GetObjectData > PD>передвигаться в потоке ? Т.е. оставить место , а потом к нему вернуться > PD>и записать значение. > > Ты волен создать свой поток и делать с ним что душа пожелает. Бинари- и Соап-форматер принимают именованные значения через SerializationInfo.AddValue(). Подсунь туда свой массив байтов или стрим.
А вот здесь, если можно, поподробнее. Мне самому вчера эта мысль в
голову пришла. Идея следующая
Открываем свой поток
Класс имплементирует ISerializable
В GetObjectData делаю следующее
AddValue(произвольное целое)
Position1 = Stream.Position // запомнили позицию
Теперь в цикле прохожу матрицу и заношу по AddValue все тройки и считаю
их количество — N3
Position2 = Stream.Position // запомнили позицию
Stream.Position = Position1
AddValue(N3) // записали вместо произвольного целого N3
Stream.Position = Position2 // и вернулись в конец
Lloyd wrote: > > Здравствуйте, Pavel Dvorkin, Вы писали: > > А почему бы просто не писать в MemoryStream. А после просто вызвать метод GetBuffer и получить все что ты туда записал в виде массива байт.
Не совсем понял. MemoryStream, как я понимаю, находится в ОП, так ? Т.е.
ты предлагаешь сначала туда записать, а потом взять байты и их
сериализовать ? Это решение не пройдет — объем данных ОЧЕНЬ большой и
НИКАКОЕ копирование их по ходу сериализации просто недопустимо.
Я понимаю (даже с моим знанием .net , что можно придумать еще много
других решений. Вообще, если этот вопрос рассматривать чисто
практически, то разумное решение находится за 1 минуту — выкинуть это N3
вообще, а в конце записать тройку (0,0,0) . Мой вопрос в другом —
можно ли перемещаться по потоку при сериализации ? Иными словами ,
сериализация — строго последовательный алгоритм или все же можно в нем
позиционироваться ?
См. также мой ответ VladD2
Poudy wrote: > > Здравствуйте, Pavel Dvorkin, Вы писали: > > PD> ...[skipped]... > > PD>Есть класс — двумерная матрица. Матрица сильно разрежена. Ее надо > PD>сохранить, но нули сохранять не надо. > > PD>Насколько я понимаю, здесь надо сериализоваться с написанием собственной > PD>ISerializable.GetObjectData > PD> и специального конструктора. Хорошо. > При сериализации в Net в поток пишешь не ты. Собственно... порядок параметров не важен. > > Сделай так: > > ArrayList rowsList = new ArrayList(/*~N*/); > .... // добавление троек.
Никакое копирование при сериализации недопустимо по причине ограничений
по памяти. См. также мои другие сегодняшние ответы.
Здравствуйте, Pavel Dvorkin, Вы писали:
>> А насколько она разрежена? Может быть есть смысл эмулировать матрицу на хэш-таблице? Например, в экселе делается именно так. Правда с трехмерной прийдется повозиться, но все же.
PD>Похоже, дело свелось к обсуждению того, как лучше эту матрицу хранить и PD>выводить.
Потому что проблема именно в этом.
PD>Можно ли при сериализации с собственной реализацией GetObjectData PD>передвигаться в потоке ?
Нет, потому что не любой поток допускает позиционирование.
AndrewVK wrote: > > Здравствуйте, Pavel Dvorkin, Вы писали: > > >> А насколько она разрежена? Может быть есть смысл эмулировать матрицу на хэш-таблице? Например, в экселе делается именно так. Правда с трехмерной прийдется повозиться, но все же. > > PD>Похоже, дело свелось к обсуждению того, как лучше эту матрицу хранить и > PD>выводить. > > Потому что проблема именно в этом. > > PD>Можно ли при сериализации с собственной реализацией GetObjectData > PD>передвигаться в потоке ? > > Нет, потому что не любой поток допускает позиционирование.
А если в GetObjectData проверять контекст и разрешать, только если это
File ?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>А если в GetObjectData проверять контекст и разрешать, только если это PD>File ?
Боюсь механика кастомной сериализации универсальная и на подобные извращения не рассчитана. Вобщем тебе правильно тут советуют — либо храни свою матрицу ввиде хешей (а для разреженной матрицы именно этот способ хранения является оптимальным), либо формируй список вершин со значениями в памяти целиком.
AndrewVK wrote: > > Здравствуйте, Pavel Dvorkin, Вы писали:
> Боюсь механика кастомной сериализации универсальная и на подобные извращения не рассчитана. Вобщем тебе правильно тут советуют — либо храни свою матрицу ввиде хешей (а для разреженной матрицы именно этот способ хранения является оптимальным), либо формируй список вершин со значениями в памяти целиком.
Понятно. Все это не проходит, так как матрица была взята только для
пояснения сути проблемы, реальную проблему я описал в одном из ответов.
Ну что же, раз нельзя, значит, нельзя.
--
With best regards,
Pavel Dvorkin
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Это корректно ?
Просто сохрани нужное тебе число с отдельным именем. А с другим именем сохрани ссылку на стрим. Когда будешь читать, то читай и то и другое, а потом уже читай свой стрим.
... << RSDN@Home 1.1.4 beta 2 >>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.