javascript对象属性的笛卡尔积 [英] Cartesian product of javascript object properties

查看:64
本文介绍了javascript对象属性的笛卡尔积的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下形式的对象(下面的简化测试用例)

I have an object of the following form (simplified test case below)

var test = {
        shirts: {
            sizes: ['large', 'medium']
            ,colors:['red', 'blue']
        }
        , trousers: {
            type: ['formal', 'casual']
            , pattern: ['plaid', 'stripes']
        }
    };

我想生成属性的笛卡尔积,以便输出是以下形式的数组:

I want to generate a cartesian product of the properties so that the output is an array of the following form:

// desired output

[ {shirts:{sizes:'large', color:'red'}, trousers:{type:'formal', pattern:'plaid'}}
  ,{shirts:{sizes:'large', color:'red'}, trousers:{type:'formal', pattern:'stripes'}}
  ,{shirts:{sizes:'large', color:'red'}, trousers:{type:'casual', pattern:'plaid'}}
  , {shirts:{sizes:'large', color:'red'}, trousers:{type:'casual', pattern:'stripes'}}
  ,{shirts:{sizes:'large', color:'blue'}, trousers:{type:'formal', pattern:'plaid'}}
..... and so on  ]

我怎样才能做到这一点?我编写了以下代码(基于对来自另一个SO帖子的数组的笛卡尔积的代码的修改)但我似乎将自己绑在试图使其工作的结。

How can I achieve this? I worked up the following code (based on a modification of code for cartesian product of array from another SO post) but I seem to be tying myself in knots trying to get this to work.

 function myCartesianProduct(input, current) {
    if (!input) { return []; }


    var head = input[Object.keys(input)[0]];

    var tail = objSlice(input);

    var output = [];


    for (var key in head) {

        for (var i = 0; i < head[key].length; i++) {

            var newCurrent = copy(current);

            newCurrent[key] = head[key][i];


            if (Object.keys(tail).length) {   //if tail.length
                var productOfTail =
                        myCartesianProduct(tail, newCurrent);
                output = output.concat(productOfTail);

            } else {
                output.push(newCurrent);

            }
        }
    }
    return output;
}


function objSlice(obj) {
    var slicedObj = angular.copy(obj);  // copy object using angularJs copy method
    delete slicedObj[Object.keys(slicedObj)[0]]; //delete the first key
    return slicedObj;
};

function copy(obj) {
        var res = {};
        for (var p in obj) res[p] = obj[p];
        return res;
    }

console.log(myCartesianProduct(test));

预先感谢您的帮助!

推荐答案

好的,让我们从一个生成给定数组产品的函数开始:

Ok, let's start with a function that generates a product of given arrays:

function product(args) {
    if(!args.length)
        return [[]];
    var prod = product(args.slice(1)), r = [];
    args[0].forEach(function(x) {
        prod.forEach(function(p) {
            r.push([x].concat(p));
        });
    });
    return r;
}

下一个使用产品 {a:[1,2],b:[3,4]} 之类的内容转换为 [{a:1,b :3},{a:1,b:4},{a:2,b:3},{a:2,b:4}]

The next one uses product to convert something like {a:[1,2], b:[3,4]} into [{a:1,b:3},{a:1,b:4},{a:2,b:3},{a:2,b:4}]:

function objectProduct(obj) {
    var keys = Object.keys(obj),
        values = keys.map(function(x) { return obj[x] });

    return product(values).map(function(p) {
        var e = {};
        keys.forEach(function(k, n) { e[k] = p[n] });
        return e;
    });
}

对于您的测试数据,您必须应用两次:

For your test data, you have to apply it twice:

var result = {};
Object.keys(test).forEach(function(k) {
    result[k] = objectProduct(test[k])
});

result = objectProduct(result);

这可以为您提供所需的输出。

This gives you the output you wanted.

这篇关于javascript对象属性的笛卡尔积的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆