Как правильно удалять данные из больших массивов

15.02.21

Разработка - Универсальные функции

Как правильно удалять данные из больших несортированных массивов

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Как правильно удалять данные из больших массивов:
.epf 7,50Kb
0
0 Скачать (1 SM) Купить за 1 850 руб.

Предположим, у нас есть некий массив, из которого нужно удалить часть элементов по условию

Массив = СгенерироватьМассив(мэлементов); 
                              
Функция СгенерироватьМассив(КоличествоЭлементов)        
    ГенераторСлучайныхЧисел = новый ГенераторСлучайныхЧисел;      
    Массив = Новый Массив;          
    Для Индекс = 1 По КоличествоЭлементов Цикл                          
        Массив.Добавить(ГенераторСлучайныхЧисел.СлучайноеЧисло(0,200) - 100);                 
    КонецЦикла;   
    Возврат Массив;
КонецФункции

Большая часть людей делает это так:


Для обратныйИндекс = - Массив.ВГраница() По 0 Цикл
   Индекс = - обратныйИндекс;
   Если Не Условие1(Массив[Индекс]) Тогда
      Массив.Удалить(Индекс);        
   КонецЕсли;
КонецЦикла;

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


Для Индекс = УдаляемыйИндекс По Массив.ВГраница() - 1 Цикл
   Массив[Индекс] = Массив[Индекс + 1];            
КонецЦикла;

Из этого следует что мы выполняем цикл в цикле.

 

Верным же способом удаления данных из массива можно назвать вот такой метод:


МаксимальныйИндекс = -1;
Для Каждого ЭлМассва Из Массив Цикл
   Если Условие1(ЭлМассва) Тогда
      МаксимальныйИндекс = МаксимальныйИндекс + 1;
      Массив[МаксимальныйИндекс] = ЭлМассва;                                                
   КонецЕсли;       
КонецЦикла;
Пока Массив.ВГраница() > МаксимальныйИндекс Цикл
   Массив.Удалить(Массив.ВГраница());               
КонецЦикла;

 

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

Важное замечание: данное рассуждение актуально только для несортированных массивов, или сортированных массивов, удаляемые значения которых будут находится в начале массива.

Во вложении обработка, показывающая график с разницей по времени выполнения обоих способов (по вертикали – время в МС, по горизонтали – количество элементов). Обработка работает на управляемых формах для любых версий платформы 8.3.

В случае с вторым алгоритмом – график прямолинейный, в случае с первым – квадратичный (не совсем, но если кому интересно, может вывести верную формулу, одной из переменных которой нужно указать процент удаляемых данных)

удаление из массивов

См. также

Универсальные функции Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

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

21.05.2024    20118    dimanich70    81    

144

Универсальные функции Программист Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Задача: вставить картинку из буфера обмена на форму средствами платформы 1С.

1 стартмани

18.03.2024    4091    3    John_d    11    

57

Универсальные функции Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пришлось помучиться с GUID-ами немного, решил поделиться опытом, мало ли кому пригодится.

12.02.2024    18051    atdonya    24    

56

Универсальные функции Программист Платформа 1С v8.3 Бесплатно (free)

На заключительных этапах, когда идет отладка или доработка интерфейса, необходимо много раз переоткрыть внешний объект. Вот один из способов автоматизации этого.

30.11.2023    5501    ke.92@mail.ru    16    

65

WEB-интеграция Универсальные функции Механизмы платформы 1С Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    14729    YA_418728146    7    

166

Пакетная печать Печатные формы Адаптация типовых решений Универсальные функции Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Абонемент ($m)

Расширение для программ 1С:Управление торговлей, 1С:Комплексная автоматизация, 1С:ERP, которое позволяет распечатывать печатные формы для непроведенных документов. Можно настроить, каким пользователям, какие конкретные формы документов разрешено печатать без проведения документа.

2 стартмани

22.08.2023    3579    56    progmaster    8    

4

Инструментарий разработчика Универсальные функции Платформа 1С v8.3 Конфигурации 1cv8 1С:Розница 2 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Зарплата и Управление Персоналом 3.x Абонемент ($m)

Копирует в буфер значения из списков, из ячеек отчетов, таблиц, настроек списков, других отборов и вставляет в выбранную настройку отбора. Работает с Объект не найден. Работает как в одной так и между разными базами 1С. Использует комбинации [Alt+C] Копировать список, [Alt+V] Вставить список. Также для копирования данных используется стандартная [Ctrl+C] (например из открытого xls, mxl, doc и т.п. файла скопировать список наименований)

1 стартмани

13.10.2022    18478    171    sapervodichka    112    

135
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. starik-2005 3087 15.02.21 11:40 Сейчас в теме
А не проще тогда просто найти элемент массива "МойМассив.Найти( Х )", после чего просто поместить в найденный элемент последний элемент массива, а потом этот последний элемент грохнуть? Типа:
    Попытка 
        МойМассив[ МойМассив.Найти( Х ) ] = МойМассив[ МойМассив.ВГраница() ];
        МойМассив.Удалить( МойМассив.ВГраница() )
    Исключение КонецПопытки;
Egovigor; Dmitrij-2; gzharkoj; VitaliyCeban; +4 Ответить
4. Def.Gh 29 24.02.21 14:09 Сейчас в теме
(1)
Попытка
МойМассив[ МойМассив.Найти( Х ) ] = МойМассив[ МойМассив.ВГраница() ];
МойМассив.Удалить( МойМассив.ВГраница() )
Исключение КонецПопытки;


Если я правильно понял о чем вы то тогда поменяется порядок элементов в массиве.
10. starik-2005 3087 24.02.21 16:19 Сейчас в теме
(4) а почему нас это должно волновать?
12. Def.Gh 29 24.02.21 18:20 Сейчас в теме
(10)
а почему нас это должно волновать?


задачи разные бывают. бывают такие где это принципиально.
и опять же - попробуйте написать полный код удаления элементов по условию из массива с использованием вашего алгоритма и сделайте замер.
2. tormozit 7229 15.02.21 14:30 Сейчас в теме
Че мелочиться, давайте проверим и другие упорядоченные коллекции. Переставлять там уже дешево не выйдет. Но зависимость длительности от количества элементов было бы интересно сопоставить.
5. Def.Gh 29 24.02.21 14:11 Сейчас в теме
(2)

2. tormozit 6222 15.02.21 14:30
Че мелочиться, давайте проверим и другие упорядоченные коллекции. Переставлять там уже дешево не выйдет. Но зависимость длительности от количества элементов было бы интересно сопоставить


если вам нечем заняться - вперед и с песней.
в статье речь идет о неупорядоченном массиве.
3. t278 58 16.02.21 02:32 Сейчас в теме
Если Условие1(ЭлМассва) Тогда
      МаксимальныйИндекс = МаксимальныйИндекс + 1;
      Массив[МаксимальныйИндекс] = ЭлМассва;                                                
   КонецЕсли;

Здесь затирается элемент?
6. Def.Gh 29 24.02.21 14:13 Сейчас в теме
(3) по сути да. в конце идет обрезание массива до нужной длинны.
7. tormozit 7229 24.02.21 14:49 Сейчас в теме
Проверил смелое предположение автора и получил другой результат - оба метода удаления работают с сопоставимой скоростью. Видимо у автора были неодинаковые условия замеров. Ниже код для консоли кода ИР

КоличествоЭлементов = 10000;
ГенераторСлучайныхЧисел = новый ГенераторСлучайныхЧисел;      
Массив = Новый Массив;          
Для Индекс = 1 По КоличествоЭлементов Цикл                          
    Массив.Добавить(ГенераторСлучайныхЧисел.СлучайноеЧисло(0,200) - 100);                 
КонецЦикла;   

ирОбщий.НачатьЗамерЛкс(, "Замер1");
Для обратныйИндекс = - Массив.ВГраница() По 0 Цикл
   Индекс = - обратныйИндекс;
   Если Истина Тогда
      Массив.Удалить(Индекс);        
   КонецЕсли;
КонецЦикла;
ирОбщий.КончитьЗамерЛкс();

/////////////////////////////////
ГенераторСлучайныхЧисел = новый ГенераторСлучайныхЧисел;      
Массив = Новый Массив;          
Для Индекс = 1 По КоличествоЭлементов Цикл                          
    Массив.Добавить(ГенераторСлучайныхЧисел.СлучайноеЧисло(0,200) - 100);                 
КонецЦикла;   

ирОбщий.НачатьЗамерЛкс(, "Замер2");
МаксимальныйИндекс = -1;
Для Каждого ЭлМассва Из Массив Цикл
   Если Истина Тогда
      МаксимальныйИндекс = МаксимальныйИндекс + 1;
      Массив[МаксимальныйИндекс] = ЭлМассва;                                                
   КонецЕсли;       
КонецЦикла;
Пока Массив.ВГраница() > МаксимальныйИндекс Цикл
   Массив.Удалить(Массив.ВГраница());               
КонецЦикла;
ирОбщий.КончитьЗамерЛкс();
Показать

Он выдает
Окончание замера "Замер1" - Длительность = 0.048с
Окончание замера "Замер2" - Длительность = 0.044с
8. Def.Gh 29 24.02.21 14:53 Сейчас в теме
(7) согласен с вашими выводами для малого количества данных. а теперь попробуйте увеличить количество данных в 1000 раз.
массив из 10000 элементов сложно назвать большим ;)
9. tormozit 7229 24.02.21 14:59 Сейчас в теме
(8) Сделал для 1000 000.
Окончание замера "Замер1" - Длительность = 4.756с
Окончание замера "Замер2" - Длительность = 4.614с
11. Def.Gh 29 24.02.21 18:19 Сейчас в теме
в вашем примере есть существенная ошибка - у вас условие - истина.
поставьте условие больше на ЭлМассва > 0
13. tormozit 7229 24.02.21 19:34 Сейчас в теме
(11) Да. Теперь получил похожую разницу. Признаю, что то интересное в этом есть. Но твой способ может и немного проиграть классическому, если большинство удаляемых элементов будут во второй половине массива. А вот если большинство будет в первой половине, то твой способ сильно выигрывает:
Коэф = 0.5; // [0;1]

КоличествоЭлементов = 100000;
ЗначениеЗаполнения = 0;
Массив = Новый Массив;          
Для Индекс = 1 По КоличествоЭлементов Цикл                          
	Массив.Добавить(ЗначениеЗаполнения);
КонецЦикла;   

ирОбщий.НачатьЗамерЛкс(, "Замер1");
Для обратныйИндекс = - Массив.ВГраница() По 0 Цикл
	Индекс = - обратныйИндекс;
	Если Индекс < КоличествоЭлементов*Коэф Тогда
		Массив.Удалить(Индекс);        
	КонецЕсли;
КонецЦикла;
ирОбщий.КончитьЗамерЛкс();

/////////////////////////////////
Массив = Новый Массив;          
Для Индекс = 1 По КоличествоЭлементов Цикл                          
	Массив.Добавить(ЗначениеЗаполнения);
КонецЦикла;   

ирОбщий.НачатьЗамерЛкс(, "Замер2");
МаксимальныйИндекс = -1;
Индекс = 0;
Для Каждого ЭлМассва Из Массив Цикл
	Если Индекс < КоличествоЭлементов*Коэф Тогда
		МаксимальныйИндекс = МаксимальныйИндекс + 1;
		Массив[МаксимальныйИндекс] = ЭлМассва;                                                
	КонецЕсли;       
	Индекс = Индекс + 1;
КонецЦикла;
Пока Массив.ВГраница() > МаксимальныйИндекс Цикл
	Массив.Удалить(Массив.ВГраница());               
КонецЦикла;
ирОбщий.КончитьЗамерЛкс();
Показать

выдает
Окончание замера "Замер1" - Длительность = 1.572с
Окончание замера "Замер2" - Длительность = 0.617с

А если увеличить размер массива в 10 раз, то разница тоже увеличивается в 10 раз:
Окончание замера "Замер1" - Длительность = 116с
Окончание замера "Замер2" - Длительность = 6с
14. Def.Gh 29 24.02.21 22:00 Сейчас в теме
(13) об чем собственно и речь. и опять же у тебя не совсем честное условие - тут будет лучше именно удалять по значению, когда мы не знаем где какое значение.
метод имеет право на жизнь, но именно когда надо сохранить порядок и данных много.
почему не рассматривал вариант создания нового массива - отвечу сразу - ОЗУ не резиновое =)
Оставьте свое сообщение