Алгоритм подбора всех комбинаций многомерного массива

1. zannv 85 14.04.21 14:12 Сейчас в теме
Нужна простая универсальная функция с рекурсией для поиска всех комбинаций значений из массива массивов. В массиве может быть произвольное количество массивов, в каждом из которых произвольное количество элементов.

Пример:

массив1: 1.1, 1.2, 1.3
массив2: 2.1, 2.2, 2.3
массив3: 3.1, 3.2.

Результат:

Массив, внутри которого массивы:

1) 1.1, 2.1, 3.1
2) 1.1, 2.1, 3.2
3) 1.1, 2.2, 3.1
4) 1.1, 2.2, 3.2
и т.д.
По теме из базы знаний
Вознаграждение за ответ
Показать полностью
Найденные решения
11. comptr 35 14.04.21 15:43 Сейчас в теме +2 $m
Зачем тут рекурсия?

1. Заводите массив "Индексы" длиной "количество массивов". Начальные значения всех элементов массива - 0.
2. Собираете строку вида "ВсеМассивы[Сч][Индексы[Сч]]" - берёте элемент с индексом Индексы[Сч] из массива ВсеМассивы[Сч].
3. Увеличиваете Индексы: если Индексы[0] нельзя увеличить (стал равен длине массива ВсеМассивы[0]), то обнуляете этот индекс и переходите к следующему. Если после этого у вас опять все индексы будут равны 0, то конец алгоритма, все возможные индексы перебрали.

&НаКлиенте
Процедура ВывестиРезультат(Команда)
	// Подготовка
	ВсеМассивы = Новый Массив;
	Для Сч = 1 По 3 Цикл
		ВсеМассивы.Добавить(Новый Массив);
	КонецЦикла;
	Для Сч = 0 По ВсеМассивы.Количество() - 1 Цикл
		Для Сч1 = 1 По 3 Цикл
			ВсеМассивы[Сч].Добавить(Сч1);
		КонецЦикла;
	КонецЦикла;
	
	// Основная часть
	
	// Хранение текущего индекса элемента каждого массива
	Индексы = Новый Массив;
	Для Сч = 1 По ВсеМассивы.Количество() Цикл
		Индексы.Добавить(0);
	КонецЦикла;
	
	Пока Истина Цикл
		ВывестиСообщение(ВсеМассивы, Индексы);		
		Если НЕ УвеличитьИндекс(ВсеМассивы, Индексы) Тогда
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

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

&НаКлиенте
Функция УвеличитьИндекс(Массивы, Индексы)	
	Результат = Ложь;
	Для Сч = 0 По Индексы.Количество() - 1 Цикл 
		// Увеличиваем текущий индекс, если это возможно
		Если Индексы[Сч] < Массивы[Сч].Количество() Тогда
			Индексы[Сч] = Индексы[Сч] + 1;
		КонецЕсли;
		// Если вышли за границу, то обнуляем его и увеличиваем следующий
		Если Индексы[Сч] = Массивы[Сч].Количество() Тогда
			Индексы[Сч] = 0;
			Продолжить;
		Иначе
			Прервать;
		КонецЕсли;		
	КонецЦикла;	
	// Если перебрали все индексы, то в конце будут одни нули.
	Для Каждого ТекИндекс Из Индексы Цикл
		Если ТекИндекс <> 0 Тогда
			Результат = Истина;
			Прервать;
		КонецЕсли;
	КонецЦикла;	
	Возврат Результат;
КонецФункции
Показать
SlavaKron; +1 Ответить
Остальные ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
2. Nubsdale 14.04.21 14:17 Сейчас в теме
(1) не совсем понял что хотите получить в итоге, но очень похоже вот на это
6. zannv 85 14.04.21 14:53 Сейчас в теме
(2) похоже, но там предполагается указание конкретного количества элементов в каждом результирующем подмассиве. В моем случае кол-во элементов внутри массива равно количеству самих массивов. Из каждого массива должен браться один вариант.
7. Nubsdale 14.04.21 14:58 Сейчас в теме
(6) в гугле есть много подобных решений. можно схожий алгоритм взять и на 1с написать
8. zannv 85 14.04.21 14:59 Сейчас в теме
(7) можно) напишите работающий алгоритм, получите вознаграждение)
3. nomad_irk 80 14.04.21 14:44 Сейчас в теме
(1) Если внутри массива будут значения ссылочного типа, то функция что должна вернуть?
4. zannv 85 14.04.21 14:48 Сейчас в теме
(3) Без привязки к ссылочным типам. Вообще не важно, что внутри каждого массива.
По моему примеру будет возврат итогового массива с массивами 1), 2) 3) 4) и тд
5. Svetlanka_sv 48 14.04.21 14:51 Сейчас в теме
Вот так?

Функция ОбходМассива(Массив)
ВыводВСтроку = "";
Для каждого Элемента из Массив Цикл

Если ТипЗнч(Элемент) = Массив Тогда
СтрокаМассива = ОбходМассива(Элемент);
Сообщить(СтрокаМассива);
Иначе
ВыводВСтроку = ВыводВСтроку + Строка(Элемент) + ", "
КонецЕсли;

КонецЦикла;
Возврат ВыводВСтроку;
КонецФункции
9. zannv 85 14.04.21 15:00 Сейчас в теме
(5) нет , у вас просто перебор элементов массива
10. Leon75 14.04.21 15:32 Сейчас в теме
Неплохо было бы уточнить терминологию. Многомерный массив или массив массивов.
Потому как при
Массив = Новый Массив(3, 3);
Массив[0][0] = 11;
Массив[0][1] = 12;
Массив[0][2] = 13;
Массив[1][0] = 21;
Массив[1][1] = 22;
Массив[1][2] = 23;
Массив[2][0] = 31;
Массив[2][1] = 32;
Показать

И при вашем Примере будет:

массив1: 1.1, 1.2, 1.3
массив2: 2.1, 2.2, 2.3
массив3: 3.1, 3.2, Неопределено

А ежели это просто:
Массив = Новый Массив;
ВложенныйМассив1 = Новый Массив;
ВложенныйМассив1.Добавить(11);
ВложенныйМассив1.Добавить(12);
ВложенныйМассив1.Добавить(13);
Массив.Добавить(ВложенныйМассив1);


То как мы поймем, что на выходе нужно 3х3, ежели у нас вложенные
произвольной длины?
11. comptr 35 14.04.21 15:43 Сейчас в теме +2 $m
Зачем тут рекурсия?

1. Заводите массив "Индексы" длиной "количество массивов". Начальные значения всех элементов массива - 0.
2. Собираете строку вида "ВсеМассивы[Сч][Индексы[Сч]]" - берёте элемент с индексом Индексы[Сч] из массива ВсеМассивы[Сч].
3. Увеличиваете Индексы: если Индексы[0] нельзя увеличить (стал равен длине массива ВсеМассивы[0]), то обнуляете этот индекс и переходите к следующему. Если после этого у вас опять все индексы будут равны 0, то конец алгоритма, все возможные индексы перебрали.

&НаКлиенте
Процедура ВывестиРезультат(Команда)
	// Подготовка
	ВсеМассивы = Новый Массив;
	Для Сч = 1 По 3 Цикл
		ВсеМассивы.Добавить(Новый Массив);
	КонецЦикла;
	Для Сч = 0 По ВсеМассивы.Количество() - 1 Цикл
		Для Сч1 = 1 По 3 Цикл
			ВсеМассивы[Сч].Добавить(Сч1);
		КонецЦикла;
	КонецЦикла;
	
	// Основная часть
	
	// Хранение текущего индекса элемента каждого массива
	Индексы = Новый Массив;
	Для Сч = 1 По ВсеМассивы.Количество() Цикл
		Индексы.Добавить(0);
	КонецЦикла;
	
	Пока Истина Цикл
		ВывестиСообщение(ВсеМассивы, Индексы);		
		Если НЕ УвеличитьИндекс(ВсеМассивы, Индексы) Тогда
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

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

&НаКлиенте
Функция УвеличитьИндекс(Массивы, Индексы)	
	Результат = Ложь;
	Для Сч = 0 По Индексы.Количество() - 1 Цикл 
		// Увеличиваем текущий индекс, если это возможно
		Если Индексы[Сч] < Массивы[Сч].Количество() Тогда
			Индексы[Сч] = Индексы[Сч] + 1;
		КонецЕсли;
		// Если вышли за границу, то обнуляем его и увеличиваем следующий
		Если Индексы[Сч] = Массивы[Сч].Количество() Тогда
			Индексы[Сч] = 0;
			Продолжить;
		Иначе
			Прервать;
		КонецЕсли;		
	КонецЦикла;	
	// Если перебрали все индексы, то в конце будут одни нули.
	Для Каждого ТекИндекс Из Индексы Цикл
		Если ТекИндекс <> 0 Тогда
			Результат = Истина;
			Прервать;
		КонецЕсли;
	КонецЦикла;	
	Возврат Результат;
КонецФункции
Показать
SlavaKron; +1 Ответить
12. zannv 85 14.04.21 16:10 Сейчас в теме
(11) То, что нужно. Спасибо
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот