Имя: Пароль:
1C
1С v8
Сопоставить (сравнить) массивы
0 dmtrpv
 
15.09.16
12:09
Подскажите по алгоритму сопоставления двух массивов.

Есть 2 одномерных массива.
Бывает первый имеет больше значений, чем второй, бывает наоборот. Нужно сопоставить массивы, чтобы в одном из них, остались только те значения, которых нет во втором.
Например, МассивПервый(1,2,3,3,7); МассивВторой (1,2,2,3,4,5).
В первом массиве должны остаться только значения 3 и 7.

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

Индекс1 = 0;    
Пока Индекс1 < Массив1Размер Цикл
        Индекс2 = 0;
        Пока Индекс2 < Всего2 Цикл
            Если Массив2[Индекс2] = Массив1[Индекс1] Тогда
                Массив2(Индекс2);
                Массив2Размер= Массив2Размер - 1;
            Иначе
                Индекс2 = Индекс2 + 1;
            КонецЕсли;
        КонецЦикла;
        Индекс1 = Индекс1 + 1;
    КонецЦикла;
1 dmtrpv
 
15.09.16
12:10
Поправил
Индекс1 = 0;    
Пока Индекс1 < Массив1Размер Цикл
        Индекс2 = 0;
        Пока Индекс2 < Массив2Размер Цикл
            Если Массив2[Индекс2] = Массив1[Индекс1] Тогда
                Массив2(Индекс2);
                Массив2Размер= Массив2Размер - 1;
            Иначе
                Индекс2 = Индекс2 + 1;
            КонецЕсли;
        КонецЦикла;
        Индекс1 = Индекс1 + 1;
    КонецЦикла;
2 Ёпрст
 
15.09.16
12:14
Добавить оба массива в ТЗ и свернуть
3 dmtrpv
 
15.09.16
12:14
(2) Можно пример?
4 dmtrpv
 
15.09.16
12:16
Я имею ввиду, как свернуть, а не добавить в ТЗ
5 Одинесю
 
15.09.16
12:16
"Нужно сопоставить массивы, чтобы в одном из них, остались только те значения, которых нет во втором.
Например, МассивПервый(1,2,3,3,7); МассивВторой (1,2,2,3,4,5).
В первом массиве должны остаться только значения 3 и 7. "
3 есть же во втором.
6 AceVi
 
15.09.16
12:19
(4) Вот люди)
Свернуть - у таб знач есть метод. смотри хелп.
7 dmtrpv
 
15.09.16
12:20
(5) Да, 3 есть во втором массиве. А в первом массиве, две штуки 3, поэтому 3  и 7 должны остаться.
8 Одинесю
 
15.09.16
12:21
Понятно, свернуть не пойдет, совпадение значений по индексу надо
9 Лефмихалыч
 
15.09.16
12:23
(8)

Граница = Мин(Массив1.Количество(), Массив2.Количество());

ОниСовпадают = Истина;
Для СчЦ=0 по Граница-1 Цикл
   Если Массив1[СчЦ]<>Массив2[СчЦ] Тогда
      ОниСовпадают = Ложь;
      Прервать;
10 dmtrpv
 
15.09.16
12:24
(8) Да, свернуть не подойдет. Есть пример алгоритма для такого сравнения? Я ничо не нашел. Какая то экзотика.
11 Лефмихалыч
 
15.09.16
12:25
>Например, МассивПервый(1,2,3,3,7); МассивВторой (1,2,2,3,4,5).
>В первом массиве должны остаться только значения 3 и 7.

почему в первом должно остаться 3 и 7, а не только 7?
12 Одинесю
 
15.09.16
12:26
(8) + Определить мин индикса, сравнивать, преобразовывать. А вот вопрос - если в первом индекс больше - значения отсекаются или остаются.
13 Одинесю
 
15.09.16
12:27
(11) Потому-что значение индекса 2 не совпадают
14 Одинесю
 
15.09.16
12:27
(12) * индекса
15 Лефмихалыч
 
15.09.16
12:29
(13) а, ну тогда в (11) заготовка. Там, где ОниСовпадают = Ложь; надо добавлять значения в третий массив, где будут храниться несовпадения
16 Одинесю
 
15.09.16
12:32
(10) В (11) хорошо показано, в (15) сказано, что нужен третий массив, куда будут пихаться все несовпадения.
17 Лефмихалыч
 
15.09.16
12:42
Свернуть, кажется, тоже можно, нужно просто уметь делить на два с остатком, ну и это будет


ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Значение");
ТЗ.Колонки.Добавить("Индекс");
ТЗ.Колонки.Добавить("Показатель");
Для СчЦ=0 по Массив1.Количество()-1 Цикл
   ЗаполнитьЗначенияСвойств(ТЗ.Добавить(), Новый Структура("Значение, Индекс, Показатель", Массив1[СчЦ], СчЦ, 5));
КонецЦикла;
Для СчЦ=0 по Массив2.Количество()-1 Цикл
   ЗаполнитьЗначенияСвойств(ТЗ.Добавить(), Новый Структура("Значение, Индекс, Показатель", Массив2[СчЦ], СчЦ, 7));
КонецЦикла;
ТЗ.Свернуть("Индекс, Значение", "Показатель");

Для каждого Строка из ТЗ Цикл
   Если Строка.Показатель%2=0 Тогда
      Сообщить(Строка.Значение);
   КонецЕсли;
КонецЦикла;



только это дохрена больше строк кода
18 dmtrpv
 
15.09.16
12:42
(16) не подходит этот алгоритм. Потому что сравнение идет по индексам, первые не совпали, сразу идет Прервать. А надо, чтобы первый индекс первого массива искал совпадения по всем индексам второго массива, начиная с первого (ну то есть с нулевого) и если нет совпадения, индекс первого массива увеличивался на 1, а если есть совпадение, тогда эти индексы в поиске больше не участвуют.
19 Лефмихалыч
 
15.09.16
12:44
(18) окуеть у тебя проблема. Ну, заплати кому-нибудь, чтобы он убрал Прервать...
20 Лефмихалыч
 
15.09.16
12:45
поездец вообще! Готовый же код дал...






Я глубоко шокирован
21 ViSo76
 
15.09.16
12:50
пПервыйМассив = Новый Массив;
пПервыйМассив.Добавить( 1 );
пПервыйМассив.Добавить( 2 );
пПервыйМассив.Добавить( 3 );
пПервыйМассив.Добавить( 3 );
пПервыйМассив.Добавить( 7 );

пВторойМассив = Новый Массив;
пВторойМассив.Добавить( 1 );
пВторойМассив.Добавить( 2 );
пВторойМассив.Добавить( 2 );
пВторойМассив.Добавить( 3 );
пВторойМассив.Добавить( 4 );
пВторойМассив.Добавить( 5 );

пТаблицаОбъединения = Новый ТаблицаЗначений;
пТаблицаОбъединения.Колонки.Добавить( "КолонкаЧисло", Новый ОписаниеТипов( "Число" ) );
пТаблицаОбъединения.Колонки.Добавить( "КолонкаИндекс", Новый ОписаниеТипов( "Число" ) );
пТаблицаОбъединения.Колонки.Добавить( "КолонкаСчетчик", Новый ОписаниеТипов( "Число" ) );

Для пИндекс = 0 По пПервыйМассив.Количество() - 1 Цикл

    пЗапись = пТаблицаОбъединения.Добавить();
    пЗапись.КолонкаЧисло = пПервыйМассив[ пИндекс ];
    пЗапись.КолонкаИндекс = пИндекс;
    пЗапись.КолонкаСчетчик = 1;

КонецЦикла;

Для пИндекс = 0 По пВторойМассив.Количество() - 1 Цикл

    пЗапись = пТаблицаОбъединения.Добавить();
    пЗапись.КолонкаЧисло = пВторойМассив[ пИндекс ];
    пЗапись.КолонкаИндекс = пИндекс;
    пЗапись.КолонкаСчетчик = 2;

КонецЦикла;

пТаблицаОбъединения.Свернуть( "КолонкаЧисло, КолонкаИндекс", "КолонкаСчетчик" );

Для Каждого пЗапись Из пТаблицаОбъединения.НайтиСтроки( Новый Структура( "КолонкаСчетчик", 1 ) ) Цикл

    Сообщить( "Индекс: " + пЗапись.КолонкаИндекс + " Число: " + пЗапись.КолонкаЧисло );

КонецЦикла;
22 dmtrpv
 
15.09.16
12:58
(22) Близко, но тоже не то.
Так как ,если, например, Массив1 состоит из (1,2,3), а Массив2 состоит из (2,1,3), то эти массивы должны "совпадать", так как все элементы встречаются в обоих массивах, хоть и в разных индексах, а код (21) тут уже не справляется.
23 ViSo76
 
15.09.16
13:01
(22) Тогда у тебя условие не правильное:

В первом массиве должны остаться только значениЕ 7.
24 ViSo76
 
15.09.16
13:02
пПервыйМассив = Новый Массив;
пПервыйМассив.Добавить( 1 );
пПервыйМассив.Добавить( 2 );
пПервыйМассив.Добавить( 3 );
пПервыйМассив.Добавить( 3 );
пПервыйМассив.Добавить( 7 );

пВторойМассив = Новый Массив;
пВторойМассив.Добавить( 1 );
пВторойМассив.Добавить( 2 );
пВторойМассив.Добавить( 2 );
пВторойМассив.Добавить( 3 );
пВторойМассив.Добавить( 4 );
пВторойМассив.Добавить( 5 );

пТаблицаОбъединения = Новый ТаблицаЗначений;
пТаблицаОбъединения.Колонки.Добавить( "КолонкаЧисло", Новый ОписаниеТипов( "Число" ) );
пТаблицаОбъединения.Колонки.Добавить( "КолонкаСчетчик", Новый ОписаниеТипов( "Число" ) );

Для пИндекс = 0 По пПервыйМассив.Количество() - 1 Цикл

    пЗапись = пТаблицаОбъединения.Добавить();
    пЗапись.КолонкаЧисло = пПервыйМассив[ пИндекс ];
    пЗапись.КолонкаСчетчик = 1;

КонецЦикла;

Для пИндекс = 0 По пВторойМассив.Количество() - 1 Цикл

    пЗапись = пТаблицаОбъединения.Добавить();
    пЗапись.КолонкаЧисло = пВторойМассив[ пИндекс ];
    пЗапись.КолонкаСчетчик = 2;

КонецЦикла;

пТаблицаОбъединения.Свернуть( "КолонкаЧисло", "КолонкаСчетчик" );

Для Каждого пЗапись Из пТаблицаОбъединения.НайтиСтроки( Новый Структура( "КолонкаСчетчик", 1 ) ) Цикл

    Сообщить( "Число: " + пЗапись.КолонкаЧисло );

КонецЦикла;
25 dmtrpv
 
15.09.16
13:11
(24) И значение 3 тоже должно остаться, так как во втором Массиве одна 3, а в первом две 3.
То есть 3 из первого массива совпала с 3 из второго массива. Теперь мы их не учитываем (или удаляем). В первом массиве осталась одна 3, а во втором теперь ее нет, также в первом массиве осталась 7, котором также нет во втором массиве. Итого результат "сравнения" должен быть 3 и 7.
26 Одинесю
 
15.09.16
13:14
(25) А если в первом массиве две тройки? Две семерки?
27 dmtrpv
 
15.09.16
13:23
(26) Если МассивПервый(1,2,3,3,7,7); МассивВторой (1,2,2,3,4,5).

Нам нужен рузультат для первого массива, он "главный".
Тогда результат сравнения: 3,7,7
Так как: в первом массиве по индексу 0 число 1, ищем его во всех индексах второго массива. Если находим, то эти индексы больше не используем (либо удаляем), если не находим, то переходим в следующему индексу первого массива.

Итого: так как во втором массиве присутствует все из первого, кроме 3,7,7.
28 ViSo76
 
15.09.16
13:39
пПервыйМассив = Новый Массив;
пПервыйМассив.Добавить( 1 );
пПервыйМассив.Добавить( 2 );
пПервыйМассив.Добавить( 3 );
пПервыйМассив.Добавить( 3 );
пПервыйМассив.Добавить( 7 );

пВторойМассив = Новый Массив;
пВторойМассив.Добавить( 1 );
пВторойМассив.Добавить( 2 );
пВторойМассив.Добавить( 2 );
пВторойМассив.Добавить( 3 );
пВторойМассив.Добавить( 4 );
пВторойМассив.Добавить( 5 );

пСравнение = Новый Соответствие;

Для пИндекс = 0 По пПервыйМассив.Количество() - 1 Цикл

    пЧисло = пПервыйМассив[ пИндекс ];
    пЧислоКакСтрока = Строка( пЧисло );
    пМассивИндексов = пСравнение[ пЧислоКакСтрока ];

    Если пМассивИндексов = Неопределено Тогда

        пМассивИндексов = Новый Массив;
        пСравнение.Вставить( пЧислоКакСтрока, пМассивИндексов );

    КонецЕсли;

    пМассивИндексов.Добавить( пИндекс );

КонецЦикла;

Для Каждого пЧисло Из пВторойМассив Цикл

    пЧислоКакСтрока = Строка( пЧисло );
    пМассивИндексов = пСравнение[ пЧислоКакСтрока ];

    Если ЗначениеЗаполнено( пМассивИндексов ) Тогда

        пМассивИндексов.Удалить( 0 );

        Если пМассивИндексов.Количество() = 0 Тогда

            пСравнение.Удалить( пЧислоКакСтрока );

        КонецЕсли;

    КонецЕсли;

КонецЦикла;

Для Каждого пЗапись Из пСравнение Цикл
    
    Для Каждого пИндекс Из пЗапись.Значение Цикл

        Сообщить( "Число: " + Формат( пПервыйМассив[ пИндекс ], "ЧДЦ=0; ЧГ=" ) + " Индекс в массиве: " + Формат( пИндекс, "ЧДЦ=0; ЧГ=" ) );

    КонецЦикла;

КонецЦикла;
29 del123
 
15.09.16
14:05
для каждого элемента из первого массива если найден такой элемент во втором массиве, удаляем оба, если нет, переходим к следующему элементу
30 dmtrpv
 
15.09.16
14:21
(30) Я понимаю. Но в этом случае, происходит сдвиг массивов по индексам на - 1, соответственно меняя размер массивов на - 1и очень сложно контролировать, чтобы текущие индексы обоих массивов при проверке на совпадение не выходили за границы обоих массивов. Поэтому и ищу готовый алгоритм. Я думал, что это что-то распространенное, математика же, но даже в сборниках алгоритмов ничего похожего не нашел.
31 ViSo76
 
15.09.16
14:24
(30) И что пример из (28) не подходит?
32 dmtrpv
 
15.09.16
14:27
(31) Спасибо.
Пока тестирую, пробуя заполнять массивы данными.
Пока отрабатывает корректно.
33 Одинесю
 
15.09.16
14:29
(30) В условии цикла у тебя типа Пока Количество() - 1 , замени 1 на переменную, при удалении элемента увеличивай ее на единицу
34 FIXXXL
 
15.09.16
14:29
суешь оба массива в ТЗ,
добавляешь колонку Колво и пишешь туда 1
сворачиваешь по колонке массивов и суммируешь по колонке Колво
выбираешь строки у которых Колво<>2
35 FIXXXL
 
15.09.16
14:32
(34) а если подумать, то Цел(Колво)<>Колво/2

так будет универсально
36 dmtrpv
 
15.09.16
14:33
(34) Можно ли реализовать циклами, без ТЗ?
37 dmtrpv
 
15.09.16
14:34
(36) Отменяю вопрос. В (28) циклами же
38 dmtrpv
 
15.09.16
14:35
(28) да, похоже то, что надо.
39 del123
 
15.09.16
14:36
(30) что проверять?
пускаешь цикл от нуля до количествомассива1
получаешь n-ый элемент первого массива
поиск во втором массиве через найти(), если элемент найден, то удаляешь оба элемента (при это количествомассива1 уменьшается) и снова получаешь n-ый элемент массива, если элемент не найден то увеличиваешь n на 1
40 del123
 
15.09.16
14:37
(34) а если в первом массиве два одинаковых числа, а во втором массиве этих чисел нет?
41 dmtrpv
 
15.09.16
14:38
(40) Тогда эти два числа должны отобразиться в результате.
42 dmtrpv
 
15.09.16
14:39
(41) Ведь они не присутствуют во втором массиве, так что они считаются не найдены.
43 FIXXXL
 
15.09.16
14:39
(40) сам-на-сам еще сравнивать надо?
44 Aistovich
 
15.09.16
14:41
выгрузить в текст, сравнить размер в байтах
45 Aistovich
 
15.09.16
14:42
ой, их еще сопоставить надо
46 Aistovich
 
15.09.16
14:43
я бы строковое что-нибудь заиспользовал бы
47 del123
 
15.09.16
14:45
(41) Ну да, а способом из (34) так не получится
48 Aistovich
 
15.09.16
14:45
две строки сравнить да и всё
49 dmtrpv
 
15.09.16
14:46
Ну вот на пальцах.
Массив1(1,3,2,2)
Массив(2,1,3,4,5)

Результат сравнения:

число 1 из Массива 1 есть в Массив2, тогда вычеркиваем
число 3 из Массив1 есть в Массив2, тогда вычеркиваем
число 2 из Массив1 есть в Массив 2, тогда вычеркиваем
Число 2 тоже есть в Массив 2, но мы его вычеркнули выше, так что он считается как раз не найденным, он и есть результат!

Дальше можно не сравнивать, так как Массив1 закончился, хотя Массив 2 больше, но нам главнее Массив1.

Результат: только число 2
50 dmtrpv
 
15.09.16
14:48
Код из (28) вроде отрабатывает корректно, но хотелось бы что-нить....попроще что ли...
51 ViSo76
 
15.09.16
14:49
(50) :) Куда ещё проще
52 dmtrpv
 
15.09.16
14:50
(51) Спасибо за помощь
53 FIXXXL
 
15.09.16
14:52
(40) суй в ТЗ уникальные значения из обоих массивов
две ТЗ, обе свернуть, затем слить в одну,
проставить Колво, свернуть и просуммировать
найти строки с Цел(Колво)<>Колво/2
54 arsik
 
гуру
15.09.16
14:53
(0) Может через списокзначений проще сделать?

//Код 1С

м1 = Новый Массив;
м2 = Новый Массив;

Сп1 = Новый СписокЗначений;
Сп2 = Новый СписокЗначений;

Сп1.ЗагрузитьЗначения(м1);
Сп2.ЗагрузитьЗначения(м2);

Индекс = Сп1.Количество()-1;
Пока Индекс >= 0 Цикл
    НайденВСп2 = Сп2.НайтиПоЗначению(Сп1[Индекс]);
    Если НайденВСп2 <> Неопределено Тогда
        Сп2.Удалить(НайденВСп2);
        Сп1.Удалить(Индекс);
    КонецЕсли;
    Индекс = Индекс-1;
КонецЦикла;

м1 = Сп1.ВыгрузитьЗначения();
55 del123
 
15.09.16
14:54
(54) ну я тоже самое и предлагал, только список значений имхо необязателен)
56 arsik
 
гуру
15.09.16
14:55
//Сори ошибка

НайденВСп2 = Сп2.НайтиПоЗначению(Сп1[Индекс]);

//Вот так правильно

НайденВСп2 = Сп2.НайтиПоЗначению(Сп1[Индекс].Значение);
57 del123
 
15.09.16
14:55
(53) Опять же, а если в первой 4 одинаковых числа, а во второй ни одного?) На 4 делить потом?:)
58 dmtrpv
 
15.09.16
14:56
Вроде бы на первый взгляд простейшая математическая задача, а вот и нифига оказывается.
59 arsik
 
гуру
15.09.16
14:57
(55) А точно. Я что то не вспомнил, что в массиве искать можно
60 del123
 
15.09.16
14:58
(58) да простая, простая :)
61 arsik
 
гуру
15.09.16
15:00
Тогда вот так
//Код 1С

м1 = Новый Массив;
м2 = Новый Массив;

Индекс = м1.Количество()-1;
Пока Индекс >= 0 Цикл
    НайденВм2 = м2.Найти(м1[Индекс]);
    Если НайденВм2 <> Неопределено Тогда
        м2.Удалить(НайденВм2);
        м1.Удалить(Индекс);
    КонецЕсли;
    Индекс = Индекс-1;
КонецЦикла;
62 dmtrpv
 
15.09.16
15:06
(61) Да, тоже пойдет. Спасибо.
Здесь можно обсудить любую тему при этом оставаясь на форуме для 1Сников, который нужен для работы. Ymryn