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; }
我正试图在 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; }