Страницы: 1
RSS
Удаление объектов (Shape) находящихся в конкретном диапазоне листа.
 
Как, при наличии множества объектов, оптимально найти и удалить один или несколько объектов находящихся в заданном диапазоне листа?

Собственно
Для простоты объект полностью в ячейке.
вариант 1
Перебор всех объектов  и  
Код
                         If Not Intersect(Shape.TopLeftCell, Cell) Is Nothing Then
                            Shape.Delete
                         End If

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

вариант 2
Удаляем полностью ячейку со сдвигом , и вставляем пустую с обратным  сдвигом.
Смущает дерготня, которая может быть даже более медленной, чем перебор всех

Какие еше есть варианты?
По вопросам из тем форума, личку не читаю.
 
А как создаются эти самые объекты? Программно?
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Дмитрий. Да, в моем случае так.  Таблицу вести? Ну а если рассматривать общий случай?
По вопросам из тем форума, личку не читаю.
 
Цитата
БМВ написал:
Таблицу вести?
Нет, какие глупости. Нет ли возможности при создании назначать фигуре конкретное имя, включающее адрес ячейки? Например: _shape_sh3.B12
Тогда можно будет просто проверять есть ли фигура с названием ячейки, входящей в нужный диапазон.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Доброе время суток
Цитата
БМВ написал:
то перебор по всем
А ничего другого по существу нет. Протестировал среди 6000 объектов время поиска около секунды. Если объектов сотни (<1000), то будет в шесть раз быстрее. Стоит ли париться над более оптимальным методом?

Можно конечно вести для каждого Shape запись информации в свойство Shape.AlternativeText для идентификации нужного. Но если удаление только по месту положения (положение картинки может и не совпадать с той информацией, которая записана в AlternativeText)... То увы, только так, ну, можно чуть другие попридумывать, но хрен редьки лучше не будет.
Изменено: Андрей VG - 20.02.2020 09:11:45
 
Цитата
Дмитрий(The_Prist) Щербаков написал:
имя, включающее адрес ячейки
Дима, вариант приемлем, но ограничение есть, нельзя вставлять строки и столбцы, тем самым менять адрес :-(, а отлавливать и переименовывать - только сложнее. В этом случае хранить в скрытом столбце (строке в зависимости о того что можно вставлять) будет проще, хотя и тут есть вариант копирования и вставки строки, и тогда дублирование объекта тоже произойдет, а инфа в ячейке останется, или опять это надо отслеживать :-(

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

Можно конечно вывести процесс удаления из частного процесса одной ячейки и проверять один раз все объекты перед циклом создания новых и удалять те, что попали под "удар" . Но вопрос был скорее общего плана.

Как вариант, способ предложенный Дмитрием можно преобразить в запись имени объекта в ячейку в котором он находится, но желательно тогда сделать его невидимым. Это не решит вопрос с копированием, но может пригодится. А вот будет ли выигрыш в скорости при этом - сказать трудно. Может и правда коллекцию перебрать не так и долго.
Изменено: БМВ - 20.02.2020 09:53:31
По вопросам из тем форума, личку не читаю.
 
Цитата
БМВ написал:
нельзя вставлять строки и столбцы
можно, если в свойствах shape будет перемещать и изменять размеры вместе с ячейками. Или хотя бы перемещать. Т.е. как бы привязать объект к ячейке. Если допустимо, конечно, перемещать при вставке строк и столбцов. Ну и всегда можно совместить: не нашли по точному соответствию - тогда в ход цикл по shape-ам.
Даже самый простой вопрос можно превратить в огромную проблему. Достаточно не уметь формулировать вопросы...
 
Цитата
БМВ написал:
Но вопрос был скорее общего плана.
Почему же - основной при массовом уничтожении. Создаёшь массив записей по числу Shape со структурой: ссылка на Shape, координаты углов в строках/столбцах системы координат ячеек. Потом просто поиск по координатам. Если отсортировать по строкам, а потом по столбцам (ну, или наоборот - нужно знать конфигурацию), то потом можно быстро бинарным поиском искать - есть ли для данной ячейки Shape и что-то с ним делать.
Цитата
БМВ написал:
в запись имени объекта в ячейку в котором он находится, но желательно тогда сделать его невидимым
Есть некоторая проблема с именами Shape - Excel никак не следит за их уникальностью. Если же у вас это обеспечено, до данные по именам Shape и адресам местоположения можно хранить в пользовательских свойствах рабочего листа, содержащего Shape, написав движок для поддержания его актуальности.
Тут в любом случае - основанная проблема отслеживание шаловливых ручек пользователя. Я тут на скорую руку вставил несколько строк/столбцов - срочно нужно было напечатать, забыл, что нужно действовать через интерфейс. Ну, поменял одну картинку на другую - тоже спешно надо было куда-то оправить...
 
Для статичной таблицы вариант Дмитрия подходит может и не идеально но весьма.  Про имена и их дубли - да это прикольно и Андрей тут прав, может оказаться что на ликвидацию последствий от шаловливых рученок или на блокировку этих действий уйдет больше ресурса, чем на варианты из #1

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

Попробую сделать тест по скорости на варианте 2 из №1. и сравнить.
По вопросам из тем форума, личку не читаю.
 
Перебор, в принципе, не так уж и долог, особенно, если не забыть вовремя выйти из цикла -  например, зачем продолжать перебирать, если объект найден и уничтожен.
Предполагаю, что Intersect не самый быстрый метод для установления факта совпадения ячеек. Например, даже сравнение адресов (а они String) дает прирост скорости примерно на треть:
Код
Shape.TopLeftCell.Address = Cell.Address
ка ведь можно сравнить и номера строк и столбцов (не проверял).
Цитата
БМВ написал:
вставляется разово пачка значений,
Можно внутри цикла перебора объектов написать цикл перебора вставляемых значений, например, хранимых в коллекции и удаляемых оттуда по мере нахождения нужных объектов. Холостой цикл будет только один...
 
Ранее делал так, довольно шустро выходило
Код
If Shape.TopLeftCell.Row >= xNew And Shape.TopLeftCell.Row <= xEnd Then...

xNew и xEnd - задаваемый диапазон строк.
Аналогично можно сделать и для столбцов.
Нет Intersect, нет String.
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
Alec Perle написал:
если не забыть вовремя выйти из цикла
это в том случае, когда есть уверенность в уникальности объекта в ячейке.
Цитата
Alec Perle написал:
Можно внутри цикла перебора …  
это не совсем ответ на вопрос, ибо есть ячейка, есть набор объектов, то что этих ячеек не одна , это уже второй вопрос.
Цитата
bedvit написал:
Ранее делал так
Виталий, ща проверю разницу в скорости, но что-то мне подсказывает, что хрен редьки .Row .Column  intersect( не слаще.
Изменено: БМВ - 20.02.2020 22:26:07
По вопросам из тем форума, личку не читаю.
 
Цитата
БМВ написал:
Row .Column  intersect( не слаще.
Верно, прогонял на 6000, задавая в поиске ячейку для последней картинки. Не тестировал, но полагаю, что и с Address будет тоже самое. Учитывая опыт, больше всего времени занимает создание объекта диапазона. На его фоне разницы можно и не заметить. Хотя может и зависеть от версии Excel. Как-то же Alec Perle получил 30% разницу.
 
Цитата
Андрей VG написал:
Как-то
Андрей, я в последнее время тест прогоняю несколько раз, часто результат отличается и сильно. Кэш там или звезды виной - не знаю.
По вопросам из тем форума, личку не читаю.
 
Цитата
БМВ написал:
при наличии множества объектов, оптимально найти и удалить один или несколько объектов
Если имя фигуры будет содержать адрес ячейки, в которую была вставлена ​​эта фигура, то найти и удалить её будет очень легко - только, вам нужно сначала навести порядок (уладить, упорядочить) в именах фигур.
 
Коллеги, будут интересны результаты теста, если кто сделает тест-файл протестирую и у себя.
«Бритва Оккама» или «Принцип Калашникова»?
 
ocet p,
Вечер капитана?  :D  
Это мы с Дмитрием обсудили. Скажем так, в том решении, что у меня , будут строки вставляться, что будет означать, что все то что сдвинулось, нужно переименовывать. что  тоже можно сделать, но ух как может оказаться более затратно в итоге.

bedvit, Виталий,
Код
For Each Shape In Cell.Parent.Shapes
'Variant 1
     If Not Intersect(Shape.TopLeftCell, Cell) Is Nothing Then
        Shape.Delete
     End If
'Variant 2
'    If Shape.Top = .Top And Shape.Left = .Left Then
'         Shape.Delete
'     End If
'Variant 3
'    If Shape.TopLeftCell.Row = Cell.Row And Shape.TopLeftCell.Column = Cell.Column Then
'         Shape.Delete
'     End If
'Variant 4
'    If Shape.TopLeftCell.Address = Cell.Address Then
'         Shape.Delete
'     End If
Next

на 600 объектах и при 100 удалениях, примерно одинаковые результаты, разницей можно пренебречь. Файл боевой, не пример, по сему выкладывать не буду.
По вопросам из тем форума, личку не читаю.
 
Цитата
БМВ написал:
Это мы с Дмитрием обсудили
Я не всё прочитал ... признаю ...

Цитата
БМВ написал:
будут строки вставляться
Что с 'Shape.Placement Property' ?

Цитата
БМВ написал:
Intersect(Shape.TopLeftCell, Cell)
Не будет ли лучше (?):
Код
If Intersect(cell, Range(shp.TopLeftCell, shp.BottomRightCell)) ...
тогда или "перед" или "зад" могут выступать за ячейку



Редакт.

??? прямо по имени ???
Код
Sub udali_kartinku_balbinku()
    Dim i%, idx%, j%, jdx%
    Dim diap, kart
    
    diap = Array("A", "B", "F", "K")
    idx = UBound(diap)
    kart = Array(1, 4, 5, 7, 9, 10, 12, 13, 17, 24)
    jdx = UBound(kart)
    
    With Sheets("List1")
        For i = 0 To idx
            For j = 0 To jdx
                .Shapes(diap(i) & "_" & kart(j) & "_kart").Delete
            Next
        Next
    End With
End Sub
Изменено: ocet p - 21.02.2020 00:39:09
 
ocet p,  
.Placement - это ничего не дает. Если закрепили что объект привязан к ячейке a1, то при вставке строки оное должно сменится на A2 …
да вопрос то не как определить границы, а как избавится от перебора всей коллекции, а замены показывают, что на фоне прочих операций -это не самое существенное.
По вопросам из тем форума, личку не читаю.
 
Набросал тест на 50 тыс. фото
Результаты (время сек., найденных позиций) на моей машине:
Variant Intersect = 2,996094                   10
Variant Row/Column = 2,765625              20
Variant Address = 2,917969                     30

Отклонения действительно небольшие.
Самый быстрый - Row/Column
далее Address
далее Intersect

Протестируйте у себя.
Тест-файл прилагаю.
«Бритва Оккама» или «Принцип Калашникова»?
 
Цитата
bedvit написал:
Набросал тест на 50 тыс. фото
Приписками занимаемся :-) может 5, а не 50.

Добавил вариантs
Код
    For Each Shape In Cell.Parent.Shapes
        With Shape.TopLeftCell
            If .Row = Cell.Row Then If .Column = Cell.Column Then x = x + 1
        End With
    Next

Код
    For Each Shape In Cell.Parent.Shapes
        If Shape.TopLeftCell.Address(False, False) = Cell.Address(False, False) Then x = x + 1
    Next

нет стабильности :-)

Два прохода

Первый
Intersect 3,578125 10
Row/Column 3,386719 20
Row/Column WITH 3,496094 30
Address 3,496094 40
Address(False) 3,578125 50
Второй
Intersect 3,558594       10
Row/Column 3,351563         20
Row/Column WITH 3,34375           30
Address 3,445313         40
Address(False) 3,472656         50
Вывод - отличия на столько малы, что можно пренебрегать ими и использовать то что нравится.
Изменено: БМВ - 21.02.2020 11:49:04
По вопросам из тем форума, личку не читаю.
 
Цитата
БМВ написал:
Приписками занимаемся :-) может 5, а не 50.
напомнило....
"-Этот гамбургер не хочешь ты...
-Я не хочу этот гамбургер.
-И эту картошку ты Йоде отдашь...
-Картошку Йоде отдам.
-И тест здесь по 5 тыс фото...
-Нет, тест... тест все таки по 50...
-По 5!
-По 50!"
Изменено: bedvit - 21.02.2020 13:06:11
«Бритва Оккама» или «Принцип Калашникова»?
 
В боевой задаче попробовал вариант с сохранением имени объекта в ячейке под объектом. Ну понятно, что удаление в 10 раз быстрее других методов. А вот при реальном использовании перед вставкой или при замене картинки, разница хоть и есть но основное время занимают остальные операции, на фоне которых уже можно и подождать.
По вопросам из тем форума, личку не читаю.
Страницы: 1
Наверх