Имя: Пароль:
1C
 
пересечение массивов - алгоритм
0 Торин
 
11.02.11
13:23
Уважаемые коллеги!
Есть ли в 1С метод (или можно ли его придумать?), позволяющий получить "пересечение массивов" - т.е. оставить в первом массиве только те элементы. которые имеются во втором БЕЗ перебора  каждого из масивов?
Задачка такая -- есть 1 массив строк (5-10) и есть 2 массив строк (~1000). Можно ли как-нить удалить из первого массива строки, которых нет во втором, без того, чтобы писать два цикла?
В каком-нить RUBY это стандартный оператор языка...
1 Живой Ископаемый
 
11.02.11
13:24
запросом.
2 Живой Ископаемый
 
11.02.11
13:25
левое соединение
3 Ненавижу 1С
 
гуру
11.02.11
13:28
(2) тогда уж внутреннее?
(0) значения уникальны в массивах?
4 Живой Ископаемый
 
11.02.11
13:30
да, внутренее.
5 73
 
11.02.11
13:34
Можно
В()

Тогда только первый в ТЗ преобразовывать...
6 Торин
 
11.02.11
13:34
а как массивы в запрос передать?
7 Торин
 
11.02.11
13:37
(3) да, уникальны
8 ReaLg
 
11.02.11
13:39
(6) В запрос можно ТаблицуЗначений передать
9 Торин
 
11.02.11
13:39
(8) а таблицуЗначений как?
10 73
 
11.02.11
13:39
(6)Преобразовать в ТЗ. ТЗ параметром. Поместить во временную таблицу. Далее пакетным запросом.
Если соединением - так обе.
Если В(&Второймассив) - второй массив передать параметром, преобразовывать в ТЗ не надо.
11 Asmody
 
11.02.11
13:43
мдя... сомнительное решение: гонять массив стачала в ТЗ, потом - на сервер во врем.таблицу, потом обратно, быстрее циклом перебрать
12 Торин
 
11.02.11
13:45
(10)Вот как "поместить во временную таблицу"? Ну тупой,я тупой... Как пакетный запрос писать я понимаю. Как в одном из запросов пакета выбрать значения из параметра?
13 73
 
11.02.11
13:47
ВЫБРАТЬ
   ТЗ1.Счет
ПОМЕСТИТЬ ТЗ1
ИЗ
   &ТЗ1 КАК ТЗ1
;

ВЫБРАТЬ
   ТЗ2.Счет
ПОМЕСТИТЬ ТЗ2
ИЗ
   &ТЗ2 КАК ТЗ2
;

ВЫБРАТЬ
   ТЗ1.Счет,
   ТЗ2.Счет КАК Счет1
ИЗ
   ТЗ1 КАК ТЗ1
       ВНУТРЕННЕЕ СОЕДИНЕНИЕ ТЗ2 КАК ТЗ2
       ПО (ТЗ2.Счет = ТЗ1.Счет)
14 73
 
11.02.11
13:49
(13)+
ВЫБРАТЬ
   ТЗ1.Счет
ПОМЕСТИТЬ ТЗ1
ИЗ
   &ТЗ1 КАК ТЗ1
;

ВЫБРАТЬ
   ТЗ1.Счет
ИЗ
   ТЗ1 КАК ТЗ1
ГДЕ    
   ТЗ1.Счет В(&Массив2)
15 Живой Ископаемый
 
11.02.11
13:49
просто наверняка массив тоже не изниоткуда взялся.
16 Торин
 
11.02.11
13:52
(13) Спасибо большое. К сожалению, никогда так не делал и даже не знал, что так можно...
Все заработало...
17 73
 
11.02.11
13:55
(16) В конфигураторе:
Справка - Поиск по справке - внешнийисточник
18 Ненавижу 1С
 
гуру
11.02.11
13:55
Для каждого Эл из М1 Цикл
 Стр = ТЗ.Добавить();
 Стр.Элемент = Эл;
 Стр.Флаг = 1;
КонецЦикла;

Для каждого Эл из М2 Цикл
 Стр = ТЗ.Добавить();
 Стр.Элемент = Эл;
 Стр.Флаг = -1;
КонецЦикла;

ТЗ.Свернуть("Элемент","Флаг");
М = ТЗ.НайтиСтроки(Новый Структура("Флаг",0));
19 Scooter
 
11.02.11
13:59
(0)всё зависит от железа и от того что вы хотите "нагрузить" сервер или клиент

как вариант, ТЗ + НайтиСтроки()
20 Торин
 
11.02.11
14:01
(18) Интересное решение...
Щас проверю, что будет работать быстрее (18) или запрос. Проверю на тех параметрах, что я указал вначале -1 массив 5-10 элементов, 2 массив - 900-1000
21 73
 
11.02.11
14:03
(20) На таких количествах ставлю на (18).
22 НЕА123
 
11.02.11
14:09
(18)+
чуть-чуть быстрее. должно быть

ТЗ.ЗагрузитьКолонку(М2,"Элемент");
ТЗ.ЗаполнитьЗначения(-1,"Флаг");

Для каждого Эл из М1 Цикл
 Стр = ТЗ.Добавить();
 Стр.Элемент = Эл;
 Стр.Флаг = 1;
КонецЦикла;


ТЗ.Свернуть("Элемент","Флаг");
М = ТЗ.НайтиСтроки(Новый Структура("Флаг",0));
23 NS
 
11.02.11
14:10
сортировка и бинарный поиск. Поиск в большем массиве элементов из меньшего.
24 NS
 
11.02.11
14:11
Хотя если в меньшем массиве строк заведомо меньше Log2 количества строк в большем массиве - тогда без сортировки, и поиск перебором.
25 Торин
 
11.02.11
14:13
(23) О, гуру подтягиваются... Сергей, при каких объемах массивов есть смысл замарачиваться с бинарным поиском?
26 73
 
11.02.11
14:18
(22) Для ЗагрузитьКолонку пустые строки всё равно создавать надо. Так что спорно...
27 Торин
 
11.02.11
14:22
Да, (18) быстрее в 2,5 раза. Видимо запрос начнет обгонять при десятках тысяч во втором и сотнях в первом массиве
28 73
 
11.02.11
14:23
(27) А какой запрос использовал?
29 NS
 
11.02.11
14:23
(25) На сортировку тратится О(N*LN(N)) операций, полсе этого на проверку бинарным поиском О(K*LN(N)) операций, К - размер меньшего массива, то есть сложность алгоритма с сортировкой N*LN(N). Если отсортируем меньший массив, то на сортировку
K*LN(К), на бинарный поиск поиск N*LN(К), то есть я ошибся - лучше сортировать меньший массив, тогда сложность (N*LN(K))

Без сортировки сложность алгоритма N*K, то есть даже если в меньшем массиве меньше 10 элементов, то лучше его отсортировать и бинарным.

Все выкладки сделаны без перевода массива в ТЗ. В случае ТЗ - встроенный поиск работает весьма быстро, и тут уже надо проводить тесты.
30 Stepa86
 
11.02.11
14:24
(13)(14)(22) а если индекс добавить?
31 НЕА123
 
11.02.11
14:25
(26)
да. правда Ваша. выигрыша по времени похоже не будет.
32 NS
 
11.02.11
14:26
(30) Добавление индекса равносильно сортировке с последующим бинарным поиском.

Вообще самое быстрое - Xbase с добавленным индексом по меньшему массиву. Могу накидать код на 7.7 (восьмерки нет под рукой)
33 73
 
11.02.11
14:26
(30) На ПОМЕСТИТЬ это не повлияет. На этом потери в основном.
34 Stepa86
 
11.02.11
14:28
(32) а не что нить вроде хэш-таблиц?
35 Торин
 
11.02.11
14:30
(32) Сергей, а накидай, а? На восьмерку я уж как-нить и сам перепишу...
36 Торин
 
11.02.11
14:31
(28)
Запрос.Текст = "ВЫБРАТЬ
                  |    таблицаМассива.Значение КАК Значение
                  |ПОМЕСТИТЬ таблицаМассива
                  |ИЗ
                  |    &таблицаМассива КАК таблицаМассива
                  |;
                  |
                  |////////////////////////////////////////////////////////////////////////////////
                  |ВЫБРАТЬ
                  |    таблицаМассива.Значение
                  |ИЗ
                  |    таблицаМассива КАК таблицаМассива
                  |ГДЕ
                  |    таблицаМассива.Значение В(&массив2)";
37 NS
 
11.02.11
14:34
(34) Расчет значения Хеш-функции по большему массиву займет больше времени, чем поиск в меньшем массиве по индексу (бинарный поиск).
38 Ненавижу 1С
 
гуру
11.02.11
14:39
еще

Для каждого Эл из М1 Цикл
 Стр = ТЗ.Добавить();
 Стр.Элемент = Эл;
КонецЦикла;

Для каждого Эл из М2 Цикл
 Стр = ТЗ.Добавить();
 Стр.Элемент = Эл;
КонецЦикла;

ТЗ.Сортировать("Элемент");
Значение = Неопределено;
М = Новый Массив;
Для каждого Эл из ТЗ Цикл
 Если Значение=Эл.Элемент Тогда
   М.Добавить(Значение);
 КонецЕсли;
 Значение = Эл.Элемент;
КонецЦикла;
39 Stepa86
 
11.02.11
14:44
(37) ты мне щас теорию рассказываешь или как это на самом деле реализовано в 1Ске? =)
40 NS
 
11.02.11
15:06
проблема в том, что создание ДБФ-а занимает времени больше 20 мс., которые уходят на поиск перебором...
Тебе нужно чтоб стало быстрее, перебора?! Именно на значениях 10 и 1000?
41 Stepa86
 
11.02.11
15:09
если массив чисто из строк и прям так нужна скорость, то может написать простенькую компоненту на более низкоуровневом и через нее? или джава скрипт заюзать...
42 73
 
11.02.11
15:11
Вариант с запросом проигрывает по той же причине.
Помещение во временную таблицу занимает время...
43 Reset
 
11.02.11
15:11
// Еще) ТЗ-таблица с 1 колонкой "Элемент"
Для каждого Эл из М1 Цикл
 ТЗ.Добавить().Элемент=Эл;
КонецЦикла;
Для каждого Эл из М2 Цикл
 ТЗ.Добавить().Элемент=Эл;
КонецЦикла;

ТЗ.Колонки.Добавить("Флаг");
ТЗ.ЗаполнитьЗначения(1,"Флаг");
ТЗ.Свернуть("Элемент","Флаг");

МассивСовпадающих=Новый массив;
Для каждого Строка из ТЗ.НайтиСтроки(Новый Структура("Флаг",2)) цикл
МассивСовпадающих.Добавить(Строка.Элемент);
КонецЦикла;
44 Reset
 
11.02.11
15:11
43+ разумеется, только для уникальных значений внутри каждого массива
45 NS
 
11.02.11
15:13
Процедура Сформировать()
    перем м1[100], м2[10000];
    Для а=1 по 100 цикл
       м1[а]="Алаверды"+а*750;
    Конеццикла;
    Для а=1 по 10000 цикл
       м2[а]="Алаверды"+а;
    КонецЦикла;
    т=_GetPerformanceCounter();                                
    Для а=1 по 100 цикл
       Для б=1 по 10000 цикл  
           Если м1[а]=м2[б] тогда
               // сообщить(м1[а]);
               прервать;
           КонецЕсли;    
       Конеццикла;
    Конеццикла;      
     т=_GetPerformanceCounter();                                
    Для а=1 по 100 цикл
       Для б=1 по 10000 цикл  
           Если м1[а]=м2[б] тогда
                // сообщить(м1[а]);
               прервать;
           КонецЕсли;    
       Конеццикла;
    Конеццикла;    
    сообщить("тупой перебор "+(_GetPerformanceCounter()-т)+" мс.");  
    т=_GetPerformanceCounter();
    Файл = СоздатьОбъект("Xbase");
    Файл.ДобавитьПоле("Name","C","100",0);
    Файл.ДобавитьИндекс("IdxName","Name",0,0,"");      
    Файл.СоздатьФайл(КаталогИБ()+"find_NS.dbf",КаталогИБ()+"\find_NS.cdx");
    Файл.ЗакрытьФайл();    
    Файл.ОткрытьФайл(КаталогИБ()+"find_NS.dbf",КаталогИБ()+"\find_NS.cdx");  
    Файл.Автосохранение(1);  
    Для а=1 по 100 цикл
       Файл.Добавить();
       Файл.Name=м1[а];
    КонецЦикла;        
    Файл.ТекущийИндекс("IdxName");
    Для б=1 по 10000 цикл
       Если Файл.Найти(м2[б],0)>0 тогда
           // сообщить(м2[б]);
           файл.удалить();
       КонецЕсли;    
    Конеццикла;
    //файл.закрытьфайл();
    сообщить("индекс "+(_GetPerformanceCounter()-т)+" мс.");
КонецПроцедуры

Если взять 100 и 10000 тогда

тупой перебор 1349 мс.
индекс 223 мс.

А если массивы как указано в (0) 10 и 1000 тогда
тупой перебор 14 мс.
индекс 155 мс. Причем Индекс - практически всё потраченное время это создание файла.
46 Торин
 
11.02.11
15:13
(40) Нет, реальные значения будут *10 = т.е сотни и десятки тысяч. Это пока тестовая задачка.
(41) Да, скорость очень важна. А на чем можно написать такую ВК? На ПИТОНе  или ПРОЛОГе ведь ВК для 1с-ки не напишешь...
47 NS
 
11.02.11
15:14
Я вот не понимаю - все вышеперечисленные извращения находят быстрее тупого перебора?
48 NS
 
11.02.11
15:14
(46) Тогда см. (45)
49 Asmody
 
11.02.11
15:16
(46) а откуда массивы взялись?
50 73
 
11.02.11
15:18
(46) Потестить на реальных данных надо.
Соотношение времён здесь озвученных решений могут существенно поменяться.
51 Stepa86
 
11.02.11
15:20
(46) только ассемблер, он быстрее!!! а вообще вроде есть шаблоны ВК на дельфях и наверняка есть примеры пересечения массивов на них же в инете... так что собрать из этого компоненту думаю будет просто и быстро
52 Торин
 
11.02.11
15:21
первый массив -это массив строк из внешнего файла, второй - это некий справочник внутри базы, значение текстового поля неограниченной длины...
53 NS
 
11.02.11
15:31
(46) В восьмерке быстро работает "соответсвие" - оно индексировано. Работает быстрее XBase. Никакого ВК не нужно, ибо время тратится только на поиск в индексированной структуре.
54 73
 
11.02.11
15:33
(52) Если там справочник, то в варианте с запросом не надо его поле выгружать в массив чтобы потом назад в запрос передавать...
Возможно быстродействия запроса будет достаточно.
55 NS
 
11.02.11
15:42
(52) Очень нехорошо сравнивать строки неограниченной длины.
56 _Atilla
 
11.02.11
15:44
ТЗ1 и ТЗ2.
Добавляешь колонку "количество"

ТЗ1 колонку "количество" заполняешь 1
ТЗ2 колонку "количество" заполняешь 2

сливаешь обе ТЗ в одну.
сворачиваешь и суммируешь по колонке "количество".

там где "количество" равно 3, значит это значение существует в обоих.
там где "количество" равно 1, значит это значение существует только в первом массиве.
там где "количество" равно 2, значит это значение существует только во втором массиве.
57 NS
 
11.02.11
15:56
(18)
тупой перебор 1363 мс.
индекс 92 мс.
ТЗ 183 мс.
Это если 100 и 10000, без времени создания XBase и ТЗ.
Если использовать структуру, то будет быстрее второго варианта. То есть код получится быстрее чем свернуть - и понятно почему - свернуть работает за N LN N А второй вариант это N LN K
58 NS
 
11.02.11
15:56
(56) смотри (57)
59 NS
 
11.02.11
16:05
+ (57) Не структуру, а соответсвие.
Я несколько лет назад проводил тесты - "соответствие" заметно быстрее XBase, то есть работать будет просто влет, быстрее не напишешь и на языках высокого уровня.
Компьютеры — это как велосипед. Только для нашего сознания. Стив Джобс