最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Map array inside object inside array into a single array - Stack Overflow

programmeradmin0浏览0评论

I have an array of objects, where each object has a property whose value is another array, like this

[
  {
    location: 'somewhere',
    location_id: 1,
    parts: [
      {
        part_id: 1,
        description: 'foo',
        qty: 1,
      }
    ]
  }
]

I need to map these arrays into a single array like this

[
  {
    part_id: 1,
    description: 'foo',
    qty: 1
  },
  {
    part_id: 2,
    description: 'bar',
    qty: 1
  }
]

I tried using reduce like newArr: arr.reduce((a,b) => a.parts.concat(b.parts)) but get the error 'Cannot read property concat of undefined.' I also tried providing the initialValue argument of reduce as an empty array but same error.

As a bonus, I will eventually need the final array to not contain duplicates of parts: I.e. if a part is in two locations, it would just bine the quantity.

Open to solutions using es6 but needs to not modify original array

I have an array of objects, where each object has a property whose value is another array, like this

[
  {
    location: 'somewhere',
    location_id: 1,
    parts: [
      {
        part_id: 1,
        description: 'foo',
        qty: 1,
      }
    ]
  }
]

I need to map these arrays into a single array like this

[
  {
    part_id: 1,
    description: 'foo',
    qty: 1
  },
  {
    part_id: 2,
    description: 'bar',
    qty: 1
  }
]

I tried using reduce like newArr: arr.reduce((a,b) => a.parts.concat(b.parts)) but get the error 'Cannot read property concat of undefined.' I also tried providing the initialValue argument of reduce as an empty array but same error.

As a bonus, I will eventually need the final array to not contain duplicates of parts: I.e. if a part is in two locations, it would just bine the quantity.

Open to solutions using es6 but needs to not modify original array

Share Improve this question edited Mar 25, 2018 at 2:06 quirky purple asked Mar 25, 2018 at 0:08 quirky purplequirky purple 2,2194 gold badges35 silver badges57 bronze badges 10
  • 2 You will need to specify an initial value. The first parameter to reduce callback is the accumulator array, so it won't have a parts property. – castletheperson Commented Mar 25, 2018 at 0:13
  • 1 [].concat(...arr.map(item => item.parts)) Doesn't create that many intermediate Arrays as the approach with reduce – Thomas Commented Mar 25, 2018 at 0:21
  • How does the result include this: part_id: 2, description: 'bar' when there's nothing in the input that resembles it? – zer00ne Commented Mar 25, 2018 at 0:49
  • I just gave one object in the array as an example to show the structure, I didn't think it would be necessary to list out multiple objects. – quirky purple Commented Mar 25, 2018 at 0:50
  • Possible duplicate of Merge/flatten an array of arrays in JavaScript? – BlackICE Commented Mar 25, 2018 at 0:58
 |  Show 5 more ments

6 Answers 6

Reset to default 2

This solution uses reduce and forEach to bine all objects in sub-arrays into a Map, with part_d as key, and the qty the result of the bined quantities. When a new part_id is found, a new object is created by spreading the part into a new object, and overriding qty with 0.

The Map is then converted back to an array by spreading the Map.values() iterator:

const data = [{"location":"somewhere","location_id":1,"parts":[{"part_id":1,"description":"foo","qty":1}]},{"location":"somewhere2","location_id":2,"parts":[{"part_id":1,"description":"foo","qty":3},{"part_id":2,"description":"bar","qty":1}]}];

const result = [...
  data.reduce((r, { parts }) => {
    (parts || []).forEach((o) => {
      r.has(o.part_id) || r.set(o.part_id, { ...o, qty: 0 });

      r.get(o.part_id).qty += o.qty;
    });

    return r;
  }, new Map())
.values()];

console.log(result);

This adds all part objects into the base and removes the parts array. It will modify the old object.

let arr = [
  {
    location: 'somewhere',
    location_id: 1,
    parts: [
      {
        part_id: 1,
        description: 'something'
      }
    ]
  }
]

arr.map(m => {
  m.parts.forEach(p => Object.assign(m, p))
  delete m.parts;
})

console.log(arr);

If you're sure you want to map the arrays and not the objects inside:

const input = [
  {
    location: 'somewhere',
    location_id: 1,
    parts: [
      {
        part_id: 1,
        description: 'something'
      }
    ]
  },
  {
    location: 'somewhere2',
    location_id: 22,
    parts: [
      {
        part_id: 2,
        description: 'something'
      }
    ]
  }
];

const mapped = input.map(outerObj => outerObj.parts[0]);
console.log(mapped);

You can use array#reduce to first join all your parts array of each object. Then use array#reduce to group each object in the result array on part_id and description and sum up the qty for each unique object. Then get all the values from this object.

const input = [ { location: 'somewhere', location_id: 1, parts: [ { part_id: 1, description: 'foo', qty: 1 } ] }, { location: 'somewhere2', location_id: 22, parts: [ { part_id: 2, description: 'something', qty: 3 } ] }, { location: 'somewhere2', location_id: 22, parts: [ { part_id: 2, description: 'something', qty: 4 } ] } ],
      result = Object.values(input.reduce((r, {parts}) => r.concat(parts),[])
        .reduce((r,o) => {
          r[`${o.part_id}_${o.description}`] = r[`${o.part_id}_${o.description}`] || {...o, qty: 0};
          r[`${o.part_id}_${o.description}`].qty += o.qty;
          return r;
        },{}));
console.log(result);

This question may have two scenarios :

  1. each location have single object under parts array.

    DEMO

let jsonObj = [
  {
    location: 'somewhere',
    location_id: 1,
    parts: [
      {
        part_id: 1,
        description: 'foo',
        qty: 1,
      }
    ]
  },
  {
    location: 'somewhere',
    location_id: 2,
    parts: [
      {
        part_id: 2,
        description: 'foo',
        qty: 1,
      }
    ]
  }
];

let res = jsonObj.map(obj => obj.parts[0]);
console.log(res);

  1. Single location have multiple objects under parts array.

    DEMO

let jsonObj = [
  {
    location: 'somewhere',
    location_id: 1,
    parts: [
      {
        part_id: 1,
        description: 'foo',
        qty: 1,
      },
      {
        part_id: 2,
        description: 'foo',
        qty: 1,
      }
    ]
  }
];

let res = jsonObj[0].parts;
console.log(res);

I had a similar situation. What worked for me is defining a new array and then array.push(part) from inside a double map function:

const input = [{
    location: 'somewhere',
    location_id: 1,
    parts: [{
        part_id: 1,
        description: 'something'
      },
      {
        part_id: 2,
        description: 'something'
      }
    ]
  },
  {
    location: 'somewhere2',
    location_id: 22,
    parts: [{
        part_id: 3,
        description: 'something'
      },
      {
        part_id: 4,
        description: 'something'
      }
    ]
  }
];

if this is your input..

var list = []
input.map(item => {
  item.parts.map(part => {
    list.push(part);
  });
});
发布评论

评论列表(0)

  1. 暂无评论