Определить поддиапазон данных на листе Calc.

Автор convas, 23 августа 2010, 23:28

0 Пользователи и 1 гость просматривают эту тему.

dr.Faust

Фига се...
Мне кажется поиск будет быстрее, чем через диспетчер гонять курсор.
Свобода информации - свобода личности!

smaharbA

через диспетчер конечно дольше скорее всего, в МСО были вправо влево и т.д. методы .End(-4162).Row и т.п.
и по скорости, оно если у вас конечно диапазон как в сабже, да и регулярные выражения это циклы
Я конечно далек от мысли... (с)

smaharbA

по скорости - можно и сравнить )))
стотыщ итераций по файлу сабжа за десять сек (есть куда оптимизировать)
Я конечно далек от мысли... (с)

JohnSUN

И в тестовом примере диапазон для исследования был не "E8:L31", а "E8:K31"... Ачепятка, похоже.

И все-таки согласен с dr.Faust - поиск, похоже, лучше. А правда, давайте меряться сравнивать!
Предлагаю такой вариант:

rem Процедура определяет прямоугольный поддиапазон с заполненными ячейками
rem внутри выделенного диапазона ячеек листа
rem Если есть хотя бы одна заполненная ячейка, изменяет выделение на найденный поддиапазон
rem В противном случае выделяет верхнюю левую клетку исходного диапазона
rem Условие головоломки от convas
rem Автор кода dr.Faust
rem Украшательства и комментарии JohnSUN
rem Использованы идеи из книги "Useful Macro Information For OpenOffice.org" By Andrew Pitonyak
Sub getSubRangeWithData()
Dim oDoc As Object ' Текущий документ (книга Calc)
Dim CC As Object ' CurrentController документа oDoc
Dim oSels As Object ' Текущее выделение (варианты: ничего, часть текста в ячейке или
' одна ячейка, один диапазон ячеек, несколько диапазонов)
Dim oSheet As Object ' Текущий (обрабатываемый) лист книги
Dim oAddress as Object ' Вспомогательная структура - адрес диапазона
Dim SrhDesc As Object ' Дескриптор поиска (в выделеном диапазоне)
Dim SrhRslt As Object ' Результат поиска
Dim l As Long, lNRanges As Long ' Счетчик цикла и количество поддиапазонов с данными
' Координаты верхнего левого и нижнего правого углов искомого поддиапазона
Dim minRow As Long, minCol As Long, maxRow As Long, maxCol As Long

oDoc = ThisComponent
' Если макрос вызван не из листа книги Calc тогда нет смысла продолжать
If NOT oDoc.SupportsService("com.sun.star.sheet.SpreadsheetDocument") Then Exit Sub

CC = oDoc.getCurrentController()
' Что выделено?
oSels = oDoc.getCurrentSelection()
' Обрабатываем только вариант с одним выделенным диапазоном ячеек, остальные игнорируем
  If IsNull(oSels) Then Exit Sub ' Ничего не выделено
  If oSels.supportsService("com.sun.star.sheet.SheetCell") Then Exit Sub ' Всего одна ячейка или ее часть
  If oSels.supportsService("com.sun.star.sheet.SheetCellRanges") Then Exit Sub ' Слишком много выделено

oSheet = oSels.getSpreadsheet() ' Текущий лист. На нем отобразим (выделим) результат работы процедуры
oAddress = oSels.getRangeAddress() ' Адрес исходного диапазона
' Минимальные значения устанавливаем по максимуму, максимальные - по минимуму:
minCol = oAddress.EndColumn
minRow = oAddress.EndRow
maxCol = oAddress.StartColumn
maxRow = oAddress.StartRow

' Создаем для исходного диапазона дескриптор поиска и настраиваем его параметры:
' "Найти с использованием регулярных выражений все ячейки в которых есть хотя бы один символ"
SrhDesc = oSels.createSearchDescriptor()
SrhDesc.SearchRegularExpression = 1
SrhDesc.SearchString = ".+"
' Если ячейки содержащие только пробелы не нужны, можно использовать другую строку поиска, например, "[:alnum:].+"

' Ищем
SrhRslt = oSels.findAll(SrhDesc)
If IsNull(SrhRslt) Then ' Поиск не дал результатов, в выделенном диапазоне нет ячеек с данными
' Выделим верхнюю левую ячейку исходного диапазона и снимем выделение (выделим пустой диапазон)
  CC.Select(oSheet.GetCellbyPosition( maxCol, maxRow))
CC.Select(oDoc.createInstance("com.sun.star.sheet.SheetCellRanges"))
Exit Sub
EndIf

' Всего в исходном диапазоне найдено поддиапазонов с данными:
lNRanges = SrhRslt.getCount()
' Один или более поддиапазонов есть. Переберем их все, уточняя координаты углов искомого поддиапазона
For l=0 To lNRanges-1
oAddress = SrhRslt.getByIndex(l).getRangeAddress() ' Адрес очередного поддиапазона
If minCol > oAddress.StartColumn Then minCol = oAddress.StartColumn
If minRow > oAddress.StartRow Then minRow = oAddress.StartRow
If maxCol < oAddress.EndColumn Then maxCol = oAddress.EndColumn
If maxRow < oAddress.EndRow Then maxRow = oAddress.EndRow
Next l
' И выделим найденный поддиапазон
CC.Select(oSheet.getCellRangeByPosition( minCol, minRow, maxCol, maxRow))
End Sub


[вложение удалено Администратором]
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

smaharbA

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

картинка в тему сделана )))
Я конечно далек от мысли... (с)

JohnSUN

#20
Так что? Сравним скорости?
"- Ты не поверишь, Боб, - вздохнул он, - как мне жаль, что твоя гнедая сломала ногу..."

Кстати, во время тестирования "замерялки" нарвался на глючок в getusedrange: не отрабатывает результат анализа пустого выделения. В смысле не может выполнить sheet.getCellRangeByPosition(minc,minr,maxc,maxr) если ни одного значения не нашла...

"Замерялка" работает просто: в B2 задаем количество итераций, выделяем диапазон для исследования и жмем кнопку старта.
Стотыщ итераций ставить не советую - я замучился ждать окончания теста, там не о десяти секундах речь идет, а о 10 перекурах как минимум. Или это у меня машинка такая слабенькая?.. ???

А забавная была задачка! На месяц неторопливого вдумчивого ковыряния... У кого-нибудь еще что-нибудь такое же есть?
PS. Улучшить Quicksort - не предлагать! Я уже видел этот вариант

[вложение удалено Администратором]
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

smaharbA

Функции в том виде не сравнимые, объявление начального диапазона и задание объектов нужно приводить к единому виду
Я конечно далек от мысли... (с)

JohnSUN

В смысле в smaharbA_Main вместо
sheet=thisComponent.getSheets().getByIndex(SheetIndex%)
reg=sheet.getCellRangeByName(addrOfStart$)

цеплять сразу диапазон reg=ThisComponent.getCurrentSelection()?

Ну, чтобы оба алгоритма стартовали с одинакового выделения и заканчивали одинаковым результатом?
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

smaharbA

и это тоже

по сути и не оспаривалась скорость в ООо (от статыщ это так сказать поговорка адинеснегов), может есть переходы как СтартРоу подобные екселевским енд(х).роу
не вызывающие мотания контроллера
Я конечно далек от мысли... (с)

JohnSUN

Ну да... Или хотя бы перерисовку на время выполнения отключить. Вроде бы где-то мелькало что-то на эту тему... Типа аналога МСОшного ScreenUpdating...

Впрочем, на малых количествах итераций разница настолько несущественна, что действительно не стоит ломать голову над дальнейшей оптимизацией.

А вообще-то мы молодцы! Чего ж это нам так мало платят-то, а?

Ну что, convas, ставим [РЕШЕНО]?
Владислав Орлов aka JohnSUN
Благодарить-не зазорно.
Подарить благо создателям офиса, нашему ресурсу, мне

smaharbA

прорисовка снова включается если появляется курсор
да и диспачер вещь отвратительная конечно, стоит скрыть лист и кабздец

Принимаю свое поражение :)
Я конечно далек от мысли... (с)

convas

Спасибо за проявленный интерес и за предложенные решения.

Способы решения, предложенные Вами, весьма познавательны.

И давайте подождем с "окончательным" [РЕШЕНО], торопиться некуда.


dr.Faust

Цитата: smaharbA от 22 сентября 2010, 20:07
да и диспачер вещь отвратительная конечно, стоит скрыть лист и кабздец
Не - не отвратительная. Просто она для других задач.

Цитата: JohnSUN от 22 сентября 2010, 17:14PS. Улучшить Quicksort - не предлагать!
Качаем всё-таки ORE, и Util  к нему, чтобы проще орентироваться.
Таки там есть КвикСорт + шейкер ;) и пробуем их обогнать.
Свобода информации - свобода личности!