【问题标题】:How to "expand" sub array in array of objects如何在对象数组中“扩展”子数组
【发布时间】:2018-08-23 15:27:10
【问题描述】:

这是我的对象数组

[{
    "key1": "value1",
    "key2": "value2",
    "key3": ["value3", "value4"]
}]

结果应该是这样的

[{
    "key1": "value1",
    "key2": "value2",
    "key3": "value3"
}, {
    "key1": "value1",
    "key2": "value2",
    "key3": "value4"
}]

所以我想去掉属性key3中的子数组,得到新的等效结构,复制所有其他属性。

由于我无法更改的原因,我应该使用 lodash,但仅限于 2.4.2 版

编辑:更详细地说:我正在使用基于 JSON 的表单引擎,它允许使用现有函数(如 lodash 函数)但不允许定义新函数。我也不能使用 for 循环之类的控制结构。本质上我只能使用链式基本函数调用,包括 lodash。

我尝试使用map,但是map不能扩展数组,它只能将一个数组元素转换成不同的东西

我可以在这里使用任何 lodash 魔法吗?

EDIT2:这里有一个例子,说明我说“我不能引入新功能”时的意思。它将检查对象数组对于某个属性子集是否是唯一的

model = [{
    "key1": "value1",
    "key2": "value2",
    "key3": "valuex"
},{
    "key1": "value1",
    "key2": "value2",
    "key3": "valuey"
}]

// will give false because the two objects are not unique regarding the combination of "key1" and "key2"
_.uniq(model.map(_.partialRight(_.pick, ["key1", "key2"])).map(JSON.stringify)).length === model.length

【问题讨论】:

  • 这听起来像是一个非常具体的案例......规则集总是一样吗?另外,它是否意味着递归?
  • 不,它只是一个级别......是的,规则集总是相同的
  • 那么[{ "key1": "value1", "key2": "value2", "key3": ["value3", "value4"], "key4":["value5","value6","value7"] }] 的期望结果是什么?
  • 正如我所说的......规则集总是相同的。这意味着,我只想扩展 key3 属性,它始终是一个数组。其他属性不应该被触及,而只是复制到新元素中
  • @devnull69 只是想知道答案是否定的?如果是这样,您能否详细说明它们如何不适合您?评论会很棒。

标签: javascript lodash


【解决方案1】:

嗯,这是一个挑战!我有一个可行的解决方案,涵盖了我能想到的所有情况,但如果有我遗漏的情况,请告诉我。


我的一般方法从最后开始,我知道我将使用_.zipObject 来创建结果对象。从那里开始,只需将其他属性与必要的key3 值对齐即可。为此,我只需复制属性值,以便key3 的每个值都有自己的副本。接下来,我将它们链接起来并创建对象。最后,我过滤掉所有不必要的对象副本。

注意:此方法不适用于key3 中的undefined 元素。我认为这是不太可能的情况,因此没有尝试解决。


可以理解的版本:

const objects = [{
    "key1": "value1",
    "key2": "value2",
    "key3": ["value3", "value4"]
},
{
    "key1": "value5",
    "key2": "value6",
    "key3": ["value7"]
}];

// Get other key names
const otherKeys = _.without(_.keys(objects[0]), "key3");
// Get values without key3
const otherValues = _.map(_.map(objects, _.partialRight(_.omit, "key3")), _.values);
// Get just key3 values
const onlyKey3 = _.map(objects, "key3");

// Generate dummy range of needed length
const maxLengthKey3 = _.max(_.map(onlyKey3, "length"));
const dummyRange = _.range(maxLengthKey3);

// Grow all arrays to needed length
const newOtherValues = _.flatten(_.map(dummyRange, _.partial(_.identity, otherValues)), true);
const newKey3 = _.flatten(_.map(dummyRange, _.partial(_.map, onlyKey3)));

const pairedValues = _.map(_.zip(newOtherValues, newKey3), _.flatten);
const resultObjects = _.map(pairedValues, _.partial(_.zipObject, _.union(otherKeys, ["key3"])));

// Filter out unnecessary objects
const result = _.filter(resultObjects, "key3");

一条龙:

const objects = [{
    "key1": "value1",
    "key2": "value2",
    "key3": ["value3", "value4"]
},
{
    "key1": "value5",
    "key2": "value6",
    "key3": ["value7"]
}];
// One line
const result = _.filter(_.map(_.map(_.zip(_.flatten(_.map(_.range(_.max(_.map(_.map(objects, "key3"), "length"))), _.partial(_.identity, _.map(_.map(objects, _.partialRight(_.omit, "key3")), _.values))), true), _.flatten(_.map(_.range(_.max(_.map(_.map(objects, "key3"), "length"))), _.partial(_.map, _.map(objects, "key3"))))), _.flatten), _.partial(_.zipObject, _.union(_.without(_.keys(objects[0]), "key3"), ["key3"]))), "key3");

性能:

我预计对于大型初始数组或较大长度 key3 而言,这会很糟糕。我对单行版本尤其不寒而栗。如果有人抱怨,我会指出这是由于执行环境的限制造成的。


这是在浏览器中通过https://npm.runkit.com/lodash 测试的,使用var _ = require('lodash@2.4.2');

【讨论】:

  • 哇,你只是统治。结果是完美的......比我能处理的要复杂一点:-) 你应该得到赏金
  • @devnull69 谢谢 :) 这是一个有趣的挑战,也非常令人抓狂。我没有意识到我是多么依赖 lambda 函数来转换对象 XD。我很高兴这对你有用!
【解决方案2】:

let obj = {
    key1: "value1",
    key2: "value2",
    key3: ["value3", "value4"]
}

let tracker = new Array(obj.key3.length)

let newObjArr = []

for (let i = 0; i < tracker.length; i++) {
  newObjArr.push({
    key1: obj.key1,
    key2: obj.key2,
    key3: obj.key3[i]
  })
}

console.log(newObjArr)

【讨论】:

    【解决方案3】:

    这是一个使用 vanilla JS 的解决方案

    let array = [{
        "key1": "value1",
        "key2": "value2",
        "key3": ["value3", "value4"]
    }, {
        "key1": "value5",
        "key2": "value6",
        "key3": ["value7", "value8"]
    }, ]
    
    const result = array.reduce((final, item) => {
        for (let i = 0; i < item.key3.length; i++) {
            final.push(Object.assign({}, item, {
                "key3": item.key3[i]
            }))
        }
        return final;
    }, []);
    
    console.log(result);

    如果您要使用 lodash,我认为等效的将是:

    const _ = require('lodash')
    const result = _.reduce(array, (final, item) => {
        _.forEach(item.key3, (key3Val) => {
            final.push(Object.assign({}, item, {
                "key3": key3Val
            }))
        })
        return final;
    }, []);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-11-11
      • 2020-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-11
      • 1970-01-01
      相关资源
      最近更新 更多