通过分组和笛卡尔积重构Javascript对象

时间:2019-01-24 09:53:19

标签: javascript arrays json lodash

我从api返回了一些原始的javascript,如下所示:

     {"Values":
    [
 {
        "fieldValue": 1,
        "fieldName": "A"
      },
      {
        "fieldValue": 2,
        "fieldName": "A"
      },
      {
        "fieldValue": "FOO",
        "fieldName": "B"
      },
      {
        "fieldValue": "BAR",
        "fieldName": "B"
      }
    ]
}

我想以一种需要属性分组,将属性转换为值以及笛卡尔连接的方式来重组它,该连接导致数组对象看起来像这样:

[{"A":1,"B":"FOO"},{"A":2,B:"FOO"},{"A":1,"B":"BAR"},{"A":2,"B":"BAR"}]

我一直在查看loDash和loDash.product库,该库很有帮助,但在那儿还不够。 _groupby给我一个数组对象,而不是对象数组:

{object:
[fieldName:"A",fieldValue:1],[fieldName:"A",fieldValue:2],[fieldName:"B",fieldValue:1],[fieldName:"B",fieldValue:2]
}

1 个答案:

答案 0 :(得分:3)

首先,使用给定的数据创建一个对象,并收集键及其值。

{
    A: [1, 2],
    C: ["FOO", "BAR"]
}

然后,获取该对象的笛卡尔积。

  

如果带有对象的数组再次调用getCartesian,则函数getCartesian会分离所有键/值对并通过迭代值来构建新的笛卡尔积,并构建新的对象。

     

这同样适用于嵌套对象。

     

该算法非常简单,因为它接受带有值的任何属性,而不仅仅是数组或对象,并保留此值并遍历数组或对象的所有其他属性。该算法保留了内部结构,仅将原始值作为给定结构的结果值。

     

一开始,它需要一个对象/数组,获取所有条目,并使用带有空对象的数组对其进行迭代。

     

空数组temp是新结果。

     

为创建新元素,迭代累加器r并收集新值。这是第一级笛卡尔乘积的组成部分。

     

对于更深层次的内容,将检查值以及“如果是对象”,然后进行递归调用,并为实际键获取新结果。

function getCartesian(object) {
    return Object.entries(object).reduce((r, [k, v]) => {
        var temp = [];
        r.forEach(s =>
            (Array.isArray(v) ? v : [v]).forEach(w =>
                (w && typeof w === 'object' ? getCartesian(w) : [w]).forEach(x =>
                    temp.push(Object.assign({}, s, { [k]: x }))
                )
            )
        );
        return temp;
    }, [{}]);
}

var data = { Values: [{ fieldValue: 1, fieldName: "A" }, { fieldValue: 2, fieldName: "A" }, { fieldValue: "FOO", fieldName: "C" }, { fieldValue: "BAR", fieldName: "C" }] },
    temp = data.Values.reduce((r, { fieldName, fieldValue }) => {
        (r[fieldName] = r[fieldName] || []).push(fieldValue);
        return r;
    }, {}),
    cartesian = getCartesian(temp);

console.log(cartesian);
.as-console-wrapper { max-height: 100% !important; top: 0; }