【前端】关于多维数组排列组合的问题
最近遇到了一个关于商品属性求组合的问题,怕我描述不好先上图:如下
1、旁边的颜色尺码什么的 数量都是不确定的(因为有可能是家电,食品,或者服装什么的)
2、右边的属性值是允许手动添加的,所以数量也是不确定的
为了规范库存啥的,所以要分别排列组合出各种规格的商品并添加库存,我现在手动取到了上面的值格式如下:
data = {color:[value1,value2,value3,....],
size:[value1,value2,value3,....],
style:[value1,value2,value3,....]
}
然后我就不知道怎么求组合了,我主要是不知道如何递归,如何创建中间变量,求各位大佬给点思路,或者给出你们的代码让我参考一下,有注释更好,感谢!!!!深夜加班,我要哭了
回答
熬夜加班不容易呀,我搜了下资料,结合别人的例子,自己写了个
你可以参考一下。
主要思路是递归组合前两个
function handleCombine(arr) { debugger
var len = arr.length;
if (len >= 2) {
//从前两个开始组合
var len1 = arr[0].length;
var len2 = arr[1].length;
var lenBoth = len1 * len2;
var items = new Array(lenBoth);
var index = 0;
//for循环构建两两组合后的数组
for (var i = 0; i < len1; i++) {
for (var j = 0; j < len2; j++) {
if (arr[0][i] instanceof Array) {
items[index] = arr[0][i].concat(arr[1][j]);
} else {
items[index] = [arr[0][i]].concat(arr[1][j]);
}
index++;
}
}
// 新组合的数组取代原来前两个数组
var newArr = new Array(len - 1);
for (var i = 2; i < arr.length; i++) {
newArr[i - 1] = arr[i];
}
newArr[0] = items;
// 再次组合前两个
return handleCombine(newArr);
} else {
return arr[0];
}
}
var data = {
color: ['color1', 'color2', 'color3'],
size: ['size1', 'size2', 'size3'],
style: ['style1', 'style2', 'style3']
}
var multiArr = []
for (key in data) {
multiArr.push(data[key])
}
console.log(handleCombine(multiArr));
凑个热闹。。。
这个数据结构只有两层,只是每一层的数量不确定。所以两层循环就够了,没有必要递归。
var data = { color: ['color1', 'color2', 'color3'],
size: ['size1', 'size2', 'size3'],
style: ['style1', 'style2', 'style3']
}
Object.values(data).reduce( (result, property) => {
return property.reduce( (acc, value) => {
return acc.concat(result.map( ele => [].concat(ele, value)));
}, []);
});
输出结果为包含对象的数组:
// 循环每一个商品属性Object.keys(data).reduce( (result, key) => {
// 循环属性的每一个值
return data[key].reduce( (acc, value) => {
// 对于第一个属性
if (!result.length) {
// 将数值转化为对象格式
return acc.concat({ [key]: value });
}
// 对于第一个之后的属性,将新的属性和值添加到已有结果,并进行拼接。
return acc.concat( result.map( ele => (Object.assign({}, ele, { [key]: value }) )));
}, []);
}, []);
let color = ['blue','red','white'];let size = ['s','m','l'];
let style = [1,2,3];
let result = [];
for (var i = 0; i < color.length; i++) {
for (var j = 0; j < size.length; j++) {
for (var k = 0; k < style.length; k++) {
result.push({
color: color[i],
size: size[j],
style: style[k]
})
}
}
}
console.log(result);
这个问题按照常规,全排列
的前提是知道对象里面的所有属性
,然后利用多种for循环
或者简便的forEach语句
进行一一配对
。
楼上已经把解决方案都列出来了,我这里说一下我的思考。
我在想能不能封装一个方法,能够自动遍历
给定对象的所有属性
所对应的值,然后将它们进行全排列。这样就不需要预先知道对象的所有key
,只要保证它的结构符合我们的要求即可。
这里要求的对象结构是:
var data = { key1: [val1, val2, ...],
key2: [val1, val2, ..],
key3: [val1, val2, ..],
...
};
经过实践,我封装出来了一个generatePropertyValueArrange(obj)
方法,只要保证这个obj这个对象的结构符合我们的要求,就能够保证输出正确的所有对应属性值的数组的全排列组合。
思路如下:
先构造出对象的所有属性所对应值的数组遍历的
forEach
语句,类似以下的语句,即obj.key1.forEach(key1 => {
obj.key2.forEach(key2 => {
...
});
});
- 然后使用
eval
来执行刚刚生成的forEach
语句,这里有点像模板引擎
的味道
完整代码如下:
// 构建符合要求的对象var data = {
color: ['red', 'blue', 'black'],
size: ['S', 'M', 'L'],
style: ['child', 'young', 'middle'],
height: ['short', 'high'],
// 这里可以添加形如key: [..., ...] 这种形式的项
};
// 调用构造方法
var dataArrange = generatePropertyValueArrange(data);
// 输出结果
console.log(dataArrange);
/*
* 生成对象的属性值的全排列
* @return array
* */
function generatePropertyValueArrange(obj) {
var objKeys = Object.keys(obj);
var length = objKeys.length;
var statementChain = ''; // forEach的语句
var num = 0; // 记录obj的key值遍历的位置,比如color为0,size为1
var result = []; // 执行结果存放的数组
getObjForEachStatement(); // 执行获取对象的forEach执行语句
console.log(statementChain); // 打印以下执行语句
eval(statementChain); // 执行生成的forEach语句
// 返回result
return result;
/*
* 具体生成执行语句的函数,主要通过修改statementChain,num和result
* */
function getObjForEachStatement() {
var key = objKeys[num];
// 比如生成:obj['color'].forEach( color => {
statementChain += "obj['"+ key +"'].forEach( "+ key +" => {\n";
// 如果已经是遍历到最后一个属性,那么push结果
if (num === length - 1) {
// 比如生成:color:color,size:size,style:style,height:height,
// 属性名称:属性值的形式
var item = objKeys.reduce((acc, curr) => {
return acc.concat([curr, ':', curr].join('')).concat(',');
}, '');
// 添加到forEach语句中
// "});".repeat(length);的作用是封闭forEach语句
statementChain += "result.push({\n\t"+ item +"\n});" + "});".repeat(length);
}
num++;
if (num < length) {
// 属性还没有遍历完,递归
getObjForEachStatement();
}
}
}
测试结果如下:
// 生成的forEach语句obj['color'].forEach( color => {
obj['size'].forEach( size => {
obj['style'].forEach( style => {
obj['height'].forEach( height => {
result.push({
color:color,size:size,style:style,height:height,
});});});});});
// 构造的全排列数组
[ { color: 'red', size: 'S', style: 'child', height: 'short' },
{ color: 'red', size: 'S', style: 'child', height: 'high' },
{ color: 'red', size: 'S', style: 'young', height: 'short' },
{ color: 'red', size: 'S', style: 'young', height: 'high' },
{ color: 'red', size: 'S', style: 'middle', height: 'short' },
{ color: 'red', size: 'S', style: 'middle', height: 'high' },
{ color: 'red', size: 'M', style: 'child', height: 'short' },
{ color: 'red', size: 'M', style: 'child', height: 'high' },
{ color: 'red', size: 'M', style: 'young', height: 'short' },
{ color: 'red', size: 'M', style: 'young', height: 'high' },
{ color: 'red', size: 'M', style: 'middle', height: 'short' },
{ color: 'red', size: 'M', style: 'middle', height: 'high' },
{ color: 'red', size: 'L', style: 'child', height: 'short' },
......
大概就这些。
总结了几位大神的答案,我自己提出了一个新的需求,我想最终的数据格式是一个成员为对象的数组,对象包含的属性就是我要使用的值,所以我消化了一下撸出了下面这段:
var data = { size: ['size1', 'size2', 'size3'],
color: ['color1', 'color2', 'color3'],
style: ['style1', 'style2', 'style3']
};
var pr = (function(data){
var aa = [];
for(var pro in data){
aa.push(pro);
}
return aa;
})(data);
Object.values(data).reduce(function(objs,props,index){
debugger
if(objs.length==0){
return props.reduce(function(oo,att){
var oob = new Object();
oob[pr[index]] = att;
return oo.concat(oob);
},[]);
}else{
var item = objs.reduce(function(ritem,oo){
var tt = props.reduce(function(subitem,att){
var oob = new Object();
for(var i in oo){
oob[i] = oo[i];
}
oob[pr[index]] = att;
subitem.push(oob);
return subitem;
},[]);
return ritem.concat(tt)
},[]);
return item;
}
},[])
关注一下~
楼上给出的都是固定的3个数组的情况下,如果数组数量并不固定是无法解决的
以上是 【前端】关于多维数组排列组合的问题 的全部内容, 来源链接: utcz.com/a/79702.html