JavaScript中的矩阵数组算法逻辑

Matrix array algorithm logic in JavaScript

我正试图在 JavaScript 中解决这个算法。考虑到最大键值为 3,如何编写考虑时间复杂度的解决方案?

input1 = [{0: "small"},{0: "large"}]
output1 = [ 'small.', 'large.']
-----------------------------------------
input2 = [ {0: "small"},{0: "large"}, {1: "red"} ]
output2 = ['small.red', 'large.red']
-----------------------------------------
input3 = [{0: "small"},{0: "large"}, {1: "red"}, {2:"cake"} ]
output3 = ['small.red.cake', 'large.red.cake'}
-----------------------------------------
input4 = [{0: "small"},{0: "large"}, {1: "red"}, {1: "orange"}, {2: "cake"} ]
output4 = ['small.red.cake', 'large.red.cake', 'small.orange.cake', 'large.orange.cake'}
------------------------------------------
input5 = [ {0: "small"},{0: "large"}, {1: "red"},{1: "orange"},{1: "blue"},{2: "cake"},{2: "ice"}]
output5 = ['small.red.cake', 'large.red.cake', 'small.orange.cake', 'large.orange.cake', 'small.blue.cake', 'large.blue.cake', 'small.red.ice', 'large.red.ice', 'small.orange.ice', 'large.orange.ice', 'small.blue.ice', 'large.blue.ice']
] //12 combinations

我的尝试:我故意在if条件下检查索引。它按预期工作。我正在寻找最佳解决方案。

const input5 = [ {0: "small"},{0: "large"}, {1: "red"},{1: "orange"},{1: "blue"},{2: "cake"},{2: "ice"}]

 let array1 = [];
let array2 = [];
let array3 = [];
input5.forEach(val => {
  if(val[0]) {
    array1.push(val[0]);
  }
  if(val[1]) {
    array2.push(val[1]);
  }
  if(val[2]) {
    array3.push(val[2]);
  }
});
const finalArray = [];
array1.forEach(val1 => {
  if(array2.length > 0) {
     array2.forEach(val2 => {
       if(array3.length > 0) {
         array3.forEach(val3 => {
           const finalVal = `${val1}.${val2}.${val3}`;
           finalArray.push(finalVal);
         })
       }else {
         const finalVal = `${val1}.${val2}`;
         finalArray.push(finalVal);
       }
     })
  }else {
    const finalVal = `${val1}.`;
    finalArray.push(finalVal);
  }
})
console.log(finalArray);

您可以构建一个包含所需索引值的数组,并获得格式化的笛卡尔积。

const
    cartesian = array => array.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), [])),
    format = array => {
        const temp = array.reduce((r, o) => {
            Object.entries(o).forEach(([i, v]) => (r[i] ??= []).push(v));
            return r;
        }, []);

        while (temp.length < 2) temp.push(['']);
        return temp;
    },
    fn = data => cartesian(format(data)).map(a => a.join('.'));

console.log(fn([{ 0: "small" },{ 0: "large" }]));
console.log(fn([{ 0: "small" }, { 0: "large" }, { 1: "red" }, { 1: "orange" }, { 2: "cake" }]));
.as-console-wrapper { max-height: 100% !important; top: 0; }

这种方法可行,但是否符合您的时间复杂度要求,我无法判断:

const inputs = [
    [{ 0: "small" }, { 0: "large" }],
    [{ 0: "small" }, { 0: "large" }, { 1: "red" }],
    [{ 0: "small" }, { 0: "large" }, { 1: "red" }, { 2: "cake" }],
    [{ 0: "small" }, { 0: "large" }, { 1: "red" }, { 1: "orange" }, { 2: "cake" }],
    [{ 0: "small" }, { 0: "large" }, { 1: "red" }, { 1: "orange" }, { 1: "blue" }, { 2: "cake" }, { 2: "ice" }],
];

function permutate(results, todo) {
    // If we have no layers left to go through, return the results
    if (!todo.length) return results;
    // Get first element of todo and store the rest for later
    const [layer, ...rest] = todo;
    // Flatmap that for example with:
    //   results = ['a', 'b']
    //   layer = [1, 2, 3]
    //  maps the results into:
    //    [ ['a.1', 'a.2', 'a.3'], ['b.1', 'b.2', 'b.3'] ]
    //  which will then be flattened together.
    results = results.flatMap(result => {
        return layer.map(value => `${result}.${value}`);
    });
    // After that, we permutate the rest of the layers
    return permutate(results, rest);
}

function getCombinations(input) {
    console.log('getCombinations for:', input);
    // Split per layer
    const layers = [];
    for (const obj of input) {
        for (const level in obj) {
            let layer = layers[level];
            if (!layer) layer = layers[level] = [];
            layer.push(obj[level]);
        }
    }
    // Now we have e.g. [ ['small', 'large'], ['red', 'orange'], ['cake', 'ice'] ]
    console.log('layers:', layers);
    // We immediately pass layer 0 as an array of results
    // then for every other layer, we build upon the (previous) results
    return permutate(layers[0], layers.slice(1));
}

for (const input of inputs) {
    console.log('========');
    const combs = getCombinations(input);
    console.log('combinations:', combs);
}

如果您输入的格式更好,那么性能会更高并且更容易编码。

相当简洁的解决方案按键分组,然后对结果的前两个元素使用修改后的 zip,直到只剩下一个元素 flat() 和 return.

function getOrderedPermutations(arr) {
  const combine = (a, b) => a.flatMap(a_ => b.map(b_ => `${a_}.${b_}`));

  let grouped = Object.values(arr.reduce((a, o) => (
    Object.entries(o).forEach(([k, v]) => (a[k] ??= []).push(v)), a), {})
  );

  let i = grouped.length - 1;
  while (i--) {
    const [a, b, ...rest] = grouped;
    grouped = [combine(a, b), ...rest];
  }

  return grouped.flat();
}

const inputs = [[{ 0: "small" }, { 0: "large" }], [{ 0: "small" }, { 0: "large" }, { 1: "red" }], [{ 0: "small" }, { 0: "large" }, { 1: "red" }, { 2: "cake" }], [{ 0: "small" }, { 0: "large" }, { 1: "red" }, { 1: "orange" }, { 2: "cake" }], [{ 0: "small" }, { 0: "large" }, { 1: "red" }, { 1: "orange" }, { 1: "blue" }, { 2: "cake" }, { 2: "ice" }],];

// Log tests
for (const input of inputs) {
  console.log('---');
  console.log('Input: ', input.map(o => `[${Object.entries(o)[0]}]`).join(', '));
  console.log('---');
  console.log(getOrderedPermutations(input), '\n');
}
.as-console-wrapper { max-height: 100% !important; top: 0; }