【前端】关于多维数组排列组合的问题

最近遇到了一个关于商品属性求组合的问题,怕我描述不好先上图:如下

【前端】关于多维数组排列组合的问题

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这个对象的结构符合我们的要求,就能够保证输出正确的所有对应属性值的数组的全排列组合。

思路如下:

  1. 先构造出对象的所有属性所对应值的数组遍历的forEach语句,类似以下的语句,即

       obj.key1.forEach(key1 => {

    obj.key2.forEach(key2 => {

    ...

    });

    });

  2. 然后使用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

回到顶部