Генерация всех комбинаций многомерного объекта - PullRequest
0 голосов
/ 26 октября 2018

Задача

Я хотел бы сгенерировать все комбинации для подобного шаблону объекта, который может принимать несколько дочерних элементов, некоторые из которых определяют желаемый результат в виде массива. У этих детей тоже могут быть дети (ограничений практически нет).

Пример ввода

const input = {
  a: [true, false],
  b: ['first', 'second'],
  c: {
    d: [true, false]
  }
};

Пример вывода

const output = [
  {
    a: true,
    b: 'first',
    c: {
      d: true
    }
  },
  {
    a: true,
    b: 'first',
    c: {
      d: false
    }
  },
  {
    a: true,
    b: 'second',
    c: {
      d: true
    }
  },
  {
    a: true,
    b: 'second',
    c: {
      d: false
    }
  },
  //...
]

Вопрос

Что может быть функцией JavaScript для преобразования ввода в вывод?

Что было испробовано?

Я попытался взять исходную функцию из этого вопроса и сделать ее более совместимой с ES, но это не работает, если в объекте есть несколько дочерних элементов.

function combinations(input, keyIndex = 0, current = {}, result = []) {
  const keys = Object.keys(input)
  const key = keys[keyIndex]
  const values = input[key]

  for (const index in values) {
    current[key] = values[index]

    if (keyIndex + 1 < keys.length) {
      combinations(input, keyIndex + 1, current, result)
    } else {
      result.push(JSON.parse(JSON.stringify(current)))
    }
  }

  return result;
}

1 Ответ

0 голосов
/ 26 октября 2018

Вы можете взять рекурсивную функцию, которая разделяет все пары ключ / значение, и построить новый декартовой продукт путем итерации значений, если массив с объектами снова вызывает getCartesian и создает новые объекты.

Это работает и для вложенных объектов.

function getCartesian(object) {
    return Object.entries(object).reduce((r, [k, v]) => {
        var temp = [];
        r.forEach(s =>
            (Array.isArray(v) ? v : [v]).forEach(w =>
                (w && typeof w === 'object' ? getCartesian(w) : [w]).forEach(x =>
                    temp.push(Object.assign({}, s, { [k]: x }))
                )
            )
        );
        return temp;
    }, [{}]);
}

var input = { a: [true, false], b: ['first', 'second'], c: { d: [true, false] } },
    cartesian = getCartesian(input);

console.log(cartesian);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...