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

15.02.21

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

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

Файлы

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

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

Подписка PRO — скачивайте любые файлы со скидкой до 85% из Базы знаний

Оформите подписку на компанию для решения рабочих задач

Оформить подписку и скачать решение со скидкой

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

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

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


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

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


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

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

 

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


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

 

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

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

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

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

Вступайте в нашу телеграмм-группу Инфостарт

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

См. также

Загрузка и выгрузка в Excel Универсальные функции Программист 1С:Предприятие 8 Россия Бесплатно (free)

Описанный ниже подход позволяет в три шага заполнять формулы в Excel файлы, вне зависимости от ОС сервера (MS Windows Server или Linux). Подход подразумевает отказ от работы с COM-объектом в пользу работы через "объектную модель документа" (DOM).

30.10.2025    3408    Abysswalker    8    

45

Универсальные функции Работа с интерфейсом Программист 1С:Предприятие 8 Бесплатно (free)

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

14.05.2025    6334    DeerCven    15    

57

Универсальные функции Программист 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

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

21.05.2024    48691    dimanich70    83    

169

Универсальные функции Программист 1С:Предприятие 8 1C:Бухгалтерия Абонемент ($m)

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

1 стартмани

18.03.2024    7295    6    John_d    13    

59

Универсальные функции Программист Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

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

12.02.2024    60886    atdonya    31    

69

Универсальные функции Программист 1С:Предприятие 8 Бесплатно (free)

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

30.11.2023    9088    ke.92@mail.ru    17    

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


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


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

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


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

Здесь затирается элемент?
6. Def.Gh 30 24.02.21 14:13 Сейчас в теме
(3) по сути да. в конце идет обрезание массива до нужной длинны.
7. tormozit 7329 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 30 24.02.21 14:53 Сейчас в теме
(7) согласен с вашими выводами для малого количества данных. а теперь попробуйте увеличить количество данных в 1000 раз.
массив из 10000 элементов сложно назвать большим ;)
9. tormozit 7329 24.02.21 14:59 Сейчас в теме
(8) Сделал для 1000 000.
Окончание замера "Замер1" - Длительность = 4.756с
Окончание замера "Замер2" - Длительность = 4.614с
11. Def.Gh 30 24.02.21 18:19 Сейчас в теме
в вашем примере есть существенная ошибка - у вас условие - истина.
поставьте условие больше на ЭлМассва > 0
13. tormozit 7329 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 30 24.02.21 22:00 Сейчас в теме
(13) об чем собственно и речь. и опять же у тебя не совсем честное условие - тут будет лучше именно удалять по значению, когда мы не знаем где какое значение.
метод имеет право на жизнь, но именно когда надо сохранить порядок и данных много.
почему не рассматривал вариант создания нового массива - отвечу сразу - ОЗУ не резиновое =)
Для отправки сообщения требуется регистрация/авторизация