#javascript #recursion
Вопрос:
Итак, у меня есть массив, который выглядит следующим образом:
['id1/id2', 'id3', 'id4/id5/id6']
Хотя в нем может быть более 3 записей или более разделенных значений (/ вещей) — они могут меняться в зависимости от состояния приложения, но это стандартный пример.
Я пытаюсь вывести:
[
['id1', 'id3', 'id4'],
['id1', 'id3', 'id5'],
['id1', 'id3', 'id6'],
['id2', 'id3', 'id4'],
['id2', 'id3', 'id5'],
['id2', 'id3', 'id6']
]
Я думаю, что цикл forEach можно использовать для рекурсии, но я застрял на синтаксисе и поэтому попробовал стандартный функциональный рекурсивный tpye. Я также не был уверен в процедуре возврата для создания выходных данных. То, что у меня есть до сих пор, — это:
singleOptionStemGenerator(route: string[]): [string[]] {
let returnArray: [string[]];
route.forEach((options: string) => {
// split into the various options
let splitOption: string[] = options.split('/');
splitOption.forEach((str: string) => {
if(route.length > 1) {
this.singleOptionStemGenerator(route.splice(0, 1));
} else {
return str;
}
})
});
return returnArray;
}
Но я не уверен, как объединить значения идентификаторов в новый массив, а затем добавить их в новый массив в целом.
РЕДАКТИРОВАТЬ: Решение, приведенное ниже для меня, было немного плотным, поэтому я прошел через него, сделал его функцией и полностью аннотировал его. Я также сделал его машинописным (который я использую). Решение-это все, что ответ на это, это просто чувствовать себя в порядке для облегчения чтения и обучения: https://codepen.io/bogomip/pen/LYLjrxa
Комментарии:
1. Здравствуйте, всегда ли количество элементов в одном столбце равно наименьшему общему кратному ?
2. Привет, Дариосицили, да, я думаю, что на выходе всегда будут элементы x * y * z, если у нас есть элементы [ x, y, z ] в массиве. Может быть, таким образом можно создать этот выходной массив, интересная мысль.
Ответ №1:
То, что вы ищете, обычно называется декартовым произведением. С помощью вспомогательной функции, которая их вычисляет, это становится почти тривиальным.
Вот одна из версий:
const cartesian = ([xs, ...xss]) =>
xs = undefined
? []
: xss.length == 0
? xs .map (x => [x])
: xs .flatMap (x => cartesian (xss) .map (ys => [x, ...ys]))
const separate = (xs) =>
cartesian (xs .map (x => x .split ('/')))
console .log (separate (['id1/id2', 'id3', 'id4/id5/id6']))
.as-console-wrapper {max-height: 100% !important; top: 0}
Обновить
В комментарии было ясно, что этот код несколько плотный. Отчасти это связано с моей склонностью к кодированию только для выражения. Для тех, кто больше привык к Javascript в стиле выражений и операторов, эта версия может быть более знакомой:
const cartesian = (xss) => {
if (xss .length == 0) {
return []
}
const first = xss [0]
const rest = xss .slice (1)
if (rest .length == 0) {
return first .map (x => [x])
}
const cartesianEnd = cartesian (rest)
return first .flatMap (
x => cartesianEnd .map (ys => [x, ...ys])
)
}
Если этот стиль вам больше по душе, то это также может помочь объяснить код, как я его написал. За исключением того, что… напечатав это, я понял, что в моем первом подходе была ужасная неэффективность. К сожалению, исправление добавляет некоторую сложность, но оно явно того стоит:
const cartesian = ([xs, ...xss]) =>
xs = undefined
? []
: xss.length == 0
? xs .map (x => [x])
: ((yss = cartesian (xss)) => xs .flatMap (x => yss .map (ys => [x, ...ys]))) ()
Проблема заключалась в том, что я пересчитывал произведение оставшихся массивов для каждого элемента моего текущего массива. Они не меняются, и мы должны сделать это только один раз. Ах, для настоящих let
привязок в JS! Мы могли бы сделать это разными способами, но этот не так уж плох.
Комментарии:
1. Я изменил кодовое обозначение с помощью решения, сделал его функцией (как и моя склонность! :)) и аннотировал его для всех, кому могут понадобиться некоторые рекомендации по этому решению: codepen.io/bogomip/pen/LYLjrxa?editors=0012
2. Мило! Обратите внимание, что «сделал это функцией» здесь немного странно. Это уже была функция, использующая синтаксис функции со стрелкой .