Имя: Пароль:
1C
1С v8
Удаление строк из таблицы значений по номеру
0 Likons
 
12.01.20
23:53
Доброго времени суток , коллеги. Пожалуйста , помогите с простой задачкой :

Есть Таблица Значений в ней есть колонка , значения в которой могут повторятся , но считать такие строки одниковыми нельзя , т.к. значение в других колонках отличаются.
Цель - удалить строки с повторяющимися значениями из таблицы.
Вот , что у меня получилось :

    НомераСтрокДляУдаления = ПоискДублейСтрокВТабЧасти(СписокДокументов,Ложь);
    Для каждого СтрокаСпискаДокументов из СписокДокументов цикл
        Для каждого Элемент из НомераСтрокДляУдаления цикл
                СписокДокументов.Удалить(Элемент.Значение);
        КонецЦикла;
    КонецЦикла;


ПоискДублейСтрокВТабЧасти - Функция , которая возвращает список значений с номерами строк , которые необходимо удалить.
СписокДокументов - Таблица , из которой эти самые строки и нужно удалить.

При попытке запуска , говорит "Значение индекса выходит за границы диапозона" , хотя номера строк 100% корректны.
Подскажите , пожалуйста , что я не так делаю ?(
1 acht
 
13.01.20
00:07
(0) У вас же, Андрей Николаевич, после удаления номера строк в таблице меняются. Вот удалили вы девятую, и хоп - на ее место встала новая, которая раньше десятая была. И все осатльны также. А вы их у себя по прежним номерам учитываете.
2 Garykom
 
гуру
13.01.20
00:30
(0) В хз какой раз повторю: Не надо удалять строки из ТЗ. Просто копируй только нужные строки в НОВУЮ ТЗ.
3 Фрэнки
 
13.01.20
00:38
и программировать намного проще - строк меньше
4 GreyK
 
13.01.20
01:14
(0) Это ты таблицу запроса редактируешь?
5 Likons
 
13.01.20
01:27
(2) (1) Спасибо вам , добрые люди , помогли ) Теперь выгружаю данные запроса во временную таблицу , а в основную таблицу добовляю строки только по условию) Еще раз , спасибо большое )
6 Chameleon1980
 
13.01.20
04:57
удали с конца
7 NUser
 
13.01.20
05:13
(0)Нужен массив с индексами строк которые нужно удалить и уже при его обходе удалять
8 NUser
 
13.01.20
05:13
..из таблицы значений
9 RomaH
 
naïve
13.01.20
07:08
(2) почему?
(0)

ТаблицаЗначений (ValueTable)
Удалить (Delete)
Вариант синтаксиса: Удаление по объекту
Синтаксис:
Удалить(<Строка>)

МассивКУдалению.Добавить(ТЗ[]);

Для каждого СтрокаТЗ Из МассивКУдалению Цикл
...
10 mzelensky
 
13.01.20
07:58
(2) Даже если в таблице 1000 строк, а удалить нужно только 1 ?
11 Сияющий в темноте
 
13.01.20
08:59
обычно,если хочется чего-то поудалять,то или обход таблицы значенийис конца или сбор удаляемых строк в массив,а потом удаление проходом по этому массиву.
12 Фрэнки
 
13.01.20
09:01
(10) так ее не только удалить нужно, но и обойти весь массив, причем, не один раз.
13 mzelensky
 
13.01.20
09:18
(12) Почему не один?

(11) (12) Делаешь обход таблицы с конца к началу и просто удаляешь строки, без каких либо массивов, в один проход.
14 Garykom
 
гуру
13.01.20
10:11
(9) (13) Потому что пора бы уже знать что платформа 1С при удалении каждой строки по одной копирует ТЗ в новое место в оперативке без этой удаленной.
15 mikecool
 
13.01.20
10:22
(14) шикарно! а это где то описано или из личных наблюдений?
16 Garykom
 
гуру
13.01.20
10:26
(15) Проведи тестирование с засеканием времени на скорость копирования ТЗ и удаления строки
17 DES
 
13.01.20
10:28
а метод Свернуть() не поможет?
18 Garykom
 
гуру
13.01.20
10:28
(16)+ Еще занятую оперативку контролируй, сделай большую ТЗ и удаляй строчек много - офигеешь как оперативка будет того ))
19 Garykom
 
гуру
13.01.20
10:30
(17) Предлагаешь добавить колонку, пронумеровать нужные строки а все ненужные свернуть в одну? Так последнюю строчку схлопнутую один хрен надо удалить потом.
Ну и Свернуть() тоже работает на копировании.
20 Garykom
 
гуру
13.01.20
10:30
(19)+ Точнее не копировании а на создании новой ТЗ
21 DES
 
13.01.20
10:36
(19) зачем что то еще удалять? Это аналогично Запрос различные.
22 Garykom
 
гуру
13.01.20
10:37
(19)+ Но метод с добавлением новой колонки правильный.

Туда пишем 1 которые нужны и 0 которые не нужны это один проход будет. Затем
ТЗ = ТЗ.Скопировать(Новый Структура("ИмяКолонки", 1))
23 DES
 
13.01.20
10:52
(22) Метод Свернуть() сам удаляет ненужные.
24 Garykom
 
гуру
13.01.20
10:53
(23) Подумай слегка или попробуй сделать
25 DES
 
13.01.20
11:02
ТаблицаОтбора = Новый ТаблицаЗначений();
        
    ТаблицаОтбора.Колонки.Добавить("Имя", Новый ОписаниеТипов("Строка"));
    ТаблицаОтбора.Колонки.Добавить("ПутьКДанным", Новый ОписаниеТипов("Строка"));
    ТаблицаОтбора.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка"));
    ТаблицаОтбора.Колонки.Добавить("ВидСравнения", Новый ОписаниеТипов("ВидСравнения"));
    ТаблицаОтбора.Колонки.Добавить("Значение");
    ТаблицаОтбора.Колонки.Добавить("ЗначениеС");
    ТаблицаОтбора.Колонки.Добавить("ЗначениеПо");
    
ТаблицаОтбора.Свернуть("Имя,ПутьКДанным,Представление,ВидСравнения,Значение,ЗначениеС,ЗначениеПо","");
26 DES
 
13.01.20
11:03
Надеюсь что дублей не будет, а ты что скажешь?
27 Garykom
 
гуру
13.01.20
11:05
(25) (26) Мы друг друга не поняли.
Согласен что для задачи ТС твой вариант лучше.

Я же говорил про произвольное удаление строк а не удаление дублирующихся по данным строк.
28 1Сергей
 
13.01.20
11:08
(0)

    НомераСтрокДляУдаления = ПоискДублейСтрокВТабЧасти(СписокДокументов,Ложь);
    //Для каждого СтрокаСпискаДокументов из СписокДокументов цикл
        Для каждого Элемент из НомераСтрокДляУдаления цикл
                СписокДокументов.Удалить(Элемент.Значение);
        КонецЦикла;
    //КонецЦикла;
29 Злопчинский
 
13.01.20
14:00
а можно отсортировать ТЗ, пройти, проставить в допколонек 1 для удаляемых (суммируем заодно счетчик удаляемых), отсортировать по возрастанию Допколонки и тупо обрезать ТЗ.КоличествоСтрок(ТЗ.КоличествоСтрок()-КолвоУдаляемых).
.
или так в 8-ке не прокатит?
30 mikecool
 
13.01.20
14:02
(16) ага, я же и говорю - в документациях такого не встречал
31 dk
 
13.01.20
14:20
переходите на 1с 77 - там нормально все с удалением из тз )
32 victuan1
 
13.01.20
19:39
(31) Нет, не нормально, тоже тормоза при удалении строки из середины ТЗ. Если речь о стандартной ТЗ, а не ИТЗ.
33 Garykom
 
гуру
13.01.20
19:45
(32) Там ТЗ тоже не на связанных списках реализована а на массивах указателей, которые ссылаются на строки.
Поэтому там в 1с 7.7 тоже самое шустрое удаление это через копирование нужных строк в новую ТЗ.

Доказано неоднократно.
34 GreyK
 
13.01.20
20:21
(29) В 8ке немного попроще, можно создать массив строк и удалить их не по номеру строки, а массив можно создать поиском в тз с отборами.
35 Злопчинский
 
13.01.20
22:03
(33) и как такое "копирование" выглядит в виде прикладного кода?
напрямую из одной ТЗ в другую ТЗ простым "копированием" - я навскидку в 77 не знаю.
без извращений - только перебором по колонкам текущей строки
Цикл По Колонкам
ТЗПолучатель.УстановитьЗначение(текстрока, текколонка,ТЗИсточник.ПолучитьЗначение(текстрока0,текколонка)
КонецЦикла;
.
или как-то хитрее можно?!?!
.
можно конечно выгруизть одну строку из тзисточник в тзбуфер, а потом
тзполучатель.заполнить(тзбуфер...)
.
но я как-то замеров не производил по сравнению быстродействия, сказать что быстрее - не могу...
36 dk
 
14.01.20
07:18
(32) (33) что-то вы гоните товарищи, никакого копирования тз при удалении строки не происходит, по крайней мере память в диспетчере не меняется у процесса
37 dk
 
14.01.20
07:20
в 1с 77
38 dmpl
 
14.01.20
07:45
(31) В 7.7 программное (средствами языка 1С) сворачивание оказывается быстрее, чем методом Свернуть(), если в ТЗ примерно 1000 строк и более. Причем разница в разы. На ТЗ из нескольких сотен тысяч строк метод Свернуть() выполняется часами, а на встроенном языке - около 1 минуты.
39 Garykom
 
гуру
14.01.20
07:55
(36) Копируются не данные в ТЗ а только таблица указателей на строки.
Данные строк на своих местах остаются лежать до момента работы сборщика мусора.

Чтобы было заметно надо сотни тысяч и миллионы строк в ТЗ и из нее удалять.
40 dk
 
14.01.20
08:01
(39) короче нормально все работает
ясень пень если удалить надо 90% то быстрее 10% загрузить в новую вместо удаления
41 Garykom
 
гуру
14.01.20
11:09
(40) Нет, если удалить надо 10% то быстрее 90% загрузить в новую.
42 ДенисЧ
 
14.01.20
11:11
(38) "Программное (средствами языка 1С) сворачивание оказывается быстрее, чем методом Свернуть()"
А свернуть() - это не средствами языка?
43 Wist
 
14.01.20
11:13
Через перебор строки из таблицы удаляются в обратном цикле (от последней строки к первой). Не благодарите
44 Wist
 
14.01.20
11:17
Если есть массив с номерами строк для удаления, то аналогично, сортируете его по убыванию и последовательно удаляете от наибольшего индекса к наименьшему
45 Злопчинский
 
14.01.20
11:32
(38) пример кода такой свертки, плиз
46 Калиостро
 
14.01.20
11:41
(38) Это что-то типа процедуры РассчитатьИтогиПоГруппам в отчете ОстаткиТМЦ в типовой ТиС?
47 dmpl
 
14.01.20
12:56
(42) Свернуть() - это средствами платформы.
48 dmpl
 
14.01.20
13:00
(45)(46) Этому коду уже лет 15, найти будет сложно. Там принцип, НЯП, был отсортировать исходную таблицу и потом обойти ее, добавляя строки в новую таблицу при изменении какого-нибудь из сворачиваемых полей и суммируя группируемые поля.
49 Злопчинский
 
15.01.20
01:08
(48) мутный алгоритм. смысл ясен, но навкидку даже туго соображаю. это по сути рекурсиваная группировка получится...
50 Сияющий в темноте
 
15.01.20
09:09
копирование таблицы указателей илм перенос указателей со сдвигом операции не столь затратные
а строка таблицы это отдельный обьект,поэтому он отдельно в памяти живет.
51 dmpl
 
15.01.20
10:55
(49) Штатный метод свертки имеет степенную зависимость времени исполнения от количества строк в таблице (т.е. при увеличении количества строк в 2 раза время выполнения увеличивается в 4 раза, при увеличении количества строк в 10 раз - время увеличивается уже в 100 раз, в итоге достаточно быстро мы упираемся в время порядка часов и дней). За показатель степени 2 не ручаюсь (давно дело было), это просто чтобы показать принцип. При программной реализации зависимость почти линейная, т.к. сортировка выполняется за достаточно малое время (в процентном отношении), а основное время занимает обход таблицы, у которого зависимость от количества строк линейная.
52 LOLYBUF
 
15.01.20
11:09
А можно занать ТЗ в менеджер временных таблиц и сделать запрос с группировкой?
53 LOLYBUF
 
15.01.20
11:09
(52) Загнать*
54 Злопчинский
 
15.01.20
12:51
(51) а попытаться найти код упоминаемый все-таки?
55 Garykom
 
гуру
15.01.20
13:24
(52) В 1С 7.7?
И даже в 1С 8 нет смысла использовать ВТ и запросы, там будут дикие потери времени на передачу в запрос и получение назад данных.
56 Сияющий в темноте
 
15.01.20
18:24
а что мы хотим от свертки?
свернуть и просуммировать или только свернуть?

опять же,линейной зависимости быть не может,нужно отсортировать,а потом пройти

если просто проходом,то будет поиск по уже существующим строкам,он хоть и индексированный,но тоже время займет.
57 LOLYBUF
 
15.01.20
19:54
(55) Понял, принял, обработал
58 Garykom
 
гуру
15.01.20
20:52
Самый быстрейший способ удаления множества строк из ТЗ (по сложному условию) или свертки ТЗ (с суммированием особо) это пока остается сериализация/десериализация средствами платформы и обработка чем то внешним.
ВК или еще что.

Если просто удалять много строк по номерам (простое условие) то копирование нужных строк в новую ТЗ по скорости равно сериализации/десериализации и внешней обработке.

Где проходит граница % строк к удалению как лучше только тестами, причем в разных версиях платформы возможно оно будет по разному.
59 Garykom
 
гуру
15.01.20
21:23
Интересно потестить когда ТЗ кидаем в ХранилищеЗначения, затем это хранилище в файл и дальше обрабатывать уже файл внешним.

Например код для 100к строк отрабатвыет у меня мгновенно


// ТЗ - таблица значений для сохранения в файл
&НаСервере
Функция ПолучитьДанныеТЗ(ТЗ)
    
    Сжатие = Новый СжатиеДанных(0);
    ДанныеТЗ = Новый ХранилищеЗначения(ТЗ.Скопировать(), Сжатие);
    Возврат XMLСтрока(ДанныеТЗ);
    
КонецФункции// ПолучитьДанныеТЗ()

// Данные - данные из файла
// ТЗ     - таблица значений куда восстанавливаем данные
&НаСервере
Процедура ЗагрузитьДанныеТЗ(Данные, ТЗ)
    
    ДанныеТЗ = XMLЗначение(Тип("ХранилищеЗначения"), Данные).Получить();
    Если ТипЗнч(ДанныеТЗ) = Тип("ТаблицаЗначений") Тогда
        ТЗ = ДанныеТЗ;
    КонецЕсли;
    
КонецПроцедуры // ЗагрузитьДанныеТЗ()

&НаСервере
Процедура Команда1НаСервере()
    // Вставить содержимое обработчика.
    
    ДанныеТЗ = Новый ТаблицаЗначений();
    ДанныеТЗ.Колонки.Добавить("УИД");
    ДанныеТЗ.Колонки.Добавить("Количество");
    
    КоличествоСрок = 100000;
    Сообщить(""+ТекущаяДата()+" Начали тест, КоличествоСрок = "+КоличествоСрок);
    
    Сообщить(""+ТекущаяДата()+" Заполнение ТЗ, начало");
    Для НомерСтроки = 1 По КоличествоСрок Цикл
        НовСтр = ДанныеТЗ.Добавить();
        
        НовСтр.УИД = "" + Новый УникальныйИдентификатор;
        НовСтр.Количество = 1;
    КонецЦикла;
    Сообщить(""+ТекущаяДата()+" Заполнение ТЗ, конец");
    
    Сообщить(""+ТекущаяДата()+" Запись ТЗ в хранилище, начало");
    ХранилищеТЗ = ПолучитьДанныеТЗ(ДанныеТЗ);
    Сообщить(""+ТекущаяДата()+" Запись ТЗ в хранилище, конец");
    
    ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
    Сообщить("Имя файла: "+ИмяВременногоФайла);
    
    Сообщить(""+ТекущаяДата()+" Запись ТЗ в файл, начало");
    ФайлТЗ = Новый ТекстовыйДокумент;
    ФайлТЗ.УстановитьТекст(ХранилищеТЗ);
    ФайлТЗ.Записать(ИмяВременногоФайла);
    Сообщить(""+ТекущаяДата()+" Запись ТЗ в файл, конец");

    Сообщить(""+ТекущаяДата()+" Закончили тест, КоличествоСрок = "+КоличествоСрок);
КонецПроцедуры
60 Garykom
 
гуру
15.01.20
21:25
(59)+ Для миллиона строк 20 секунд
15.01.2020 21:24:24 Начали тест, КоличествоСрок = 1 000 000
15.01.2020 21:24:24 Заполнение ТЗ, начало
15.01.2020 21:24:35 Заполнение ТЗ, конец
15.01.2020 21:24:35 Запись ТЗ в хранилище, начало
Имя файла: C:\Users\Gary\AppData\Local\Temp\v8_B07B_67.tmp
15.01.2020 21:24:43 Запись ТЗ в файл, начало
15.01.2020 21:24:44 Запись ТЗ в файл, конец
15.01.2020 21:24:44 Закончили тест, КоличествоСрок = 1 000 000

Размер файла 103 метра
61 Garykom
 
гуру
15.01.20
21:27
(60)+ Осталось расхреначить формат ТЗ внутри хранилища чтобы обработать некой ВК и обратная загрузка сча потестю.
62 Garykom
 
гуру
15.01.20
21:31
(61) Читает тоже замечательно в ТЗ из файла, всего 4 секунды для ляма строк
63 Garykom
 
гуру
15.01.20
21:34
Для хранилища поставил сжатие 0, но файл непонятного вида
https://i.paste.pics/b0c7691f94720bcd708587bdeba4b30f.png

Как бы это дело того, внутри ТЗ лежит.
64 Garykom
 
гуру
15.01.20
21:44
(63)+ Хехе, для двух строчек:

{"#",acf6192e-81ca-46ef-93a6-5a6968b78663,
{9,
{2,
{0,"",
{"Pattern"},"",0},
{1,"",
{"Pattern"},"",0}
},
{2,2,0,0,1,1,
{1,2,
{2,0,2,
{"S","c3fd8ff4-f441-4190-bc9e-7fc523d12e0a"},
{"N",1},0},
{2,1,2,
{"S","3eb5a58a-7f9f-4956-af80-5355ee24dca5"},
{"N",1},0}
},-1,1},
{0,0}
}
}

Короче base64 это если начало отрезать, странно что сам не догадался раз XMLСтрока
А внутри обычное ЗначениеВСтрокуВнутр
65 Злопчинский
 
17.01.20
20:24
ну это ты потестил только один вариант...
а удалить по массиву удаляемых строк?
а удалить сортировокй, поиском первого отрезаемого и отрезкой количествоСтрок(сколькооставить) если такое работает в 8-ке?
.. и прочие варианты?
66 Garykom
 
гуру
17.01.20
21:20
(65) Глубоко пофиг.
Если все эти действия выполнять снаружи чем то типа С++ то там от 1С уже не зависит и можно добиться максимально возможной на железе скорости.
67 Злопчинский
 
17.01.20
22:03
(66) ну так речь про то чтобы выполнять внутри 1С
68 Garykom
 
гуру
17.01.20
22:44
(67) Тогда нет ничего лучше чем копировать нужные строки в новую ТЗ тупо по одной.
Компьютеры — прекрасное средство для решения проблем, которых до их появления не было.