【问题标题】:How do I can split an array of objects that contains another arrays by Lodash如何通过 Lodash 拆分包含另一个数组的对象数组
【发布时间】:2017-09-25 08:39:15
【问题描述】:

我有这个数组:[{ name: "A1", arr: [1,2] }, { name: "A2", arr: [1] }]

如何将第一个对象拆分为应仅包含一个数组值的两个对象?

结果应该是:

[{name: "A1", arr: [1] }, {name: "A1", arr: [2]}, {name: "A2", arr: [1] }]

我没有在 lodash 文档中找到任何可以帮助解决此问题的通用工具。 (实际上我很少使用 lodash,所以这就是我要求帮助我的原因)。

感谢您的帮助!

【问题讨论】:

  • 我会使用 reduce 函数。如果你愿意,我可以给你一个示例解决方案。

标签: javascript arrays json collections lodash


【解决方案1】:

这是一个带有#Array.reduce函数的方法:

[{ name: "A1", arr: [1,2] }, { name: "A2", arr: [1] }].reduce((acc, val) => {
   val.arr.forEach(el => {
     acc.push({name: val.name, arr: [el]});
   });
   return acc;
}, [])

编辑

@Ian Segers 建议使用 mapconcat(谢谢):

[{ name: "A1", arr: [1,2] }, { name: "A2", arr: [1] }].reduce((acc, val) => 
  acc.concat(val.arr.map(el => {
     return  {name: val.name, arr: [el]}
   })), [])

最好的问候,

【讨论】:

  • 您可以将val.arr.forEach 更改为val.arr.map,但在这种情况下,您的推送需要替换为concat 等。
  • 我认为你也应该返回那个,所以return acc.concat(...)
  • 箭头函数这样做是因为没有括号(如果我正确理解你的意思)
  • 没错,我没有注意到你没有使用括号,给我自己的好提示:D
  • 谢谢你们的帮助!
【解决方案2】:

使用Array#map 循环数据,使用第二个Array#map 创建单独的对象,然后通过展开结果并在它们上使用Array#concat 来展平它们:

var data = [{ name: "A1", arr: [1,2] }, { name: "A2", arr: [1] }];

var result = [].concat(...data.map((item) => item.arr.map((num) => Object.assign({}, item, { arr: [num] }))));

console.log(result);

【讨论】:

  • 感谢 Ori 的回答!
【解决方案3】:

假设属性是静态的,您可以使用以下解决方案。

var arr = [{ name: "A1", arr: [1,2] }, { name: "A2", arr: [1] }], res = [];
    arr.forEach(v => v.arr.length > 1 ? v.arr.forEach(c => res.push({name: v.name, arr: [c]})) : res.push(v));
    
    console.log(JSON.stringify(res));

【讨论】:

  • Reduce 更干净 imo,因此您无需声明这个单独的 res 变量。
  • @IanSegers “你不需要声明这个单独的 res 变量” - 你怎么能确定 OP 想要改变他的原始数组?
  • 我可能误解了一些东西,如果您使用reduce,您并没有改变原始数组,而是返回一个新数组。
  • @IanSegers 没错。但无论如何,您仍然必须声明一个新的、单独的变量来保存结果,不是吗?
  • 没错,我的错,我只是喜欢在声明的时候分配一个变量。但这是我个人的喜好,我同意,最后,你需要为结果声明一个额外的变量
【解决方案4】:

您可以将数组的项目映射到一个对象中,并将外部名称属性映射到新结果集,正如ryeballar of Flatten an nested array of objects using Lodash 的答案所建议的那样。

var data = [{ name: "A1", arr: [1, 2] }, { name: "A2", arr: [1] }],
    result = _.flatMap(data, 
        item => _.map(_.map(item.arr,
            v => ({ arr: [v] })
        ), prop => _.defaults({ name: item.name }, prop)));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>

ES6 与 Object.assign

var data = [{ name: "A1", arr: [1, 2] }, { name: "A2", arr: [1] }],
    result = data.reduce(
        (r, a) => r.concat(a.arr.map(b => Object.assign({}, a, { arr: [b] })))
    , []);

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

【讨论】:

  • 谢谢妮娜的回答!
【解决方案5】:

通常我想采用.reduce() 的方式,但它在概念上是错误的。这是错误的,因为 reduce 用于减少,如果我们将其用于扩展,那么我们必须使用副作用,这不是一个合适的函数方法。然而...在 JS 中没有功能性工具可以处理此类任务。

所以只是为了好玩,让我们发明一个。 Array.unfold()

Arrays.unfold(p,f,t,v) 接受 4 个参数。

  • p 这是一个定义停止位置的函数。 p 函数像许多数组仿函数一样接受 3 个参数。值、索引和当前生成的数组。它应返回一个布尔值。当它返回 true 时,递归迭代停止。
  • f 这是一个返回下一项功能值的函数。
  • t 这是一个函数,用于在下一回合将下一个参数返回给 f
  • sf用来计算索引0的舒适座位的种子值。

所以现在我们可以为所需的情况实现展开的 Array 构造函数。

Array.unfold = function(p,f,t,s){
  var res = [],
   runner = v =>  p(v,res.length-1,res) ? [] : (res = res.concat(f(v)), runner(t(v)), res);
  return runner(s);
};

var data   = [{ name: "A1", arr: [1,2] }, { name: "A2", arr: [1] }],
    result = Array.unfold(v => v.length === 0,
                          v => v[0].arr.map(n => Object.assign({},v[0],{arr:[n]})),
                          v => v.slice(1),
                          data);
console.log(JSON.stringify(result));

【讨论】:

  • 感谢热度的帮助!
猜你喜欢
  • 1970-01-01
  • 2023-03-22
  • 2020-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-21
  • 2019-05-05
  • 1970-01-01
相关资源
最近更新 更多