Предварительная/функциональная рекурсия и возвращаемые значения

#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. Мило! Обратите внимание, что «сделал это функцией» здесь немного странно. Это уже была функция, использующая синтаксис функции со стрелкой .