18

I have this array of objects, within it I have another array of objects:

[
  {
    id: 1,
    country: [
      {
        id: "5a60626f1d41c80c8d3f8a85"
      },
      {
        id: "5a6062661d41c80c8b2f0413"
      }
    ]
  },
  {
    id: 2,
    country: [
      {
        id: "5a60626f1d41c80c8d3f8a83"
      },
      {
        id: "5a60626f1d41c80c8d3f8a84"
      }
    ]
  }
];

How to get flat array of country like this:

[
  { id: "5a60626f1d41c80c8d3f8a85" },
  { id: "5a6062661d41c80c8b2f0413" },
  { id: "5a60626f1d41c80c8d3f8a83" },
  { id: "5a60626f1d41c80c8d3f8a84" }
];

without using a forEach and a temp variable?

When I did:

(data || []).map(o=>{
  return o.country.map(o2=>({id: o2.id}))
})

I got the same structure back.

6 Answers 6

36

Latest edit

All modern JS environments now support Array.prototype.flat and Array.prototype.flatMap

const data=[{id:1,country:[{id:"5a60626f1d41c80c8d3f8a85"},{id:"5a6062661d41c80c8b2f0413"}]},{id:2,country:[{id:"5a60626f1d41c80c8d3f8a83"},{id:"5a60626f1d41c80c8d3f8a84"}]}];

console.log(
  data.flatMap(
    (elem) => elem.country
  )
)


Old answer

No need for any ES6 magic, you can just reduce the array by concatenating inner country arrays.

const data=[{id:1,country:[{id:"5a60626f1d41c80c8d3f8a85"},{id:"5a6062661d41c80c8b2f0413"}]},{id:2,country:[{id:"5a60626f1d41c80c8d3f8a83"},{id:"5a60626f1d41c80c8d3f8a84"}]}];

console.log(
  data.reduce(
    (arr, elem) => arr.concat(elem.country), []
  )
)

If you want an ES6 feature (other than an arrow function), use array spread instead of the concat method:

const data=[{id:1,country:[{id:"5a60626f1d41c80c8d3f8a85"},{id:"5a6062661d41c80c8b2f0413"}]},{id:2,country:[{id:"5a60626f1d41c80c8d3f8a83"},{id:"5a60626f1d41c80c8d3f8a84"}]}];

console.log(
  data.reduce(
    (arr, elem) => [...arr, ...elem.country], []
  )
)

Note: These suggestions would create a new array on each iteration.

For efficiency, you have to sacrifice some elegance:

const data=[{id:1,country:[{id:"5a60626f1d41c80c8d3f8a85"},{id:"5a6062661d41c80c8b2f0413"}]},{id:2,country:[{id:"5a60626f1d41c80c8d3f8a83"},{id:"5a60626f1d41c80c8d3f8a84"}]}];

console.log(
  data.reduce(
    (arr, elem) => {
      for (const c of elem.country) {
        arr.push(c);
      }
      return arr;
    }, []
  )
)

Sign up to request clarification or add additional context in comments.

3 Comments

spread work if my country only have id property, which usually is not the case.
what if I want ['id1','id2','id3','id4'] will I still use reduce?
You can just insert country.map(({ id }) => id) instead of country in any of the examples.
3

const raw = [
  {
    id: 1,
    country: [
      {
        id: "5a60626f1d41c80c8d3f8a85"
      },
      {
        id: "5a6062661d41c80c8b2f0413"
      }
    ]
  },
  {
    id: 2,
    country: [
      {
        id: "5a60626f1d41c80c8d3f8a83"
      },
      {
        id: "5a60626f1d41c80c8d3f8a84"
      }
    ]
  }
];

const countryIds = raw
                    .map(x => x.country)
                    .reduce((acc, curr) => {
                      return [
                        ...acc, 
                        ...curr.map(x => x.id)
                      ];
                    }, []);
console.log(countryIds)

Comments

0

This, works, just concat the nested arrays returned by your solution

let arr = [{    "id": 1,
    "country": [{
        "id": "5a60626f1d41c80c8d3f8a85",
      },
      {
        "id": "5a6062661d41c80c8b2f0413",
      }
    ]
  },
  {
    "id": 2,
    "country": [{
        "id": "5a60626f1d41c80c8d3f8a83",
      },
      {
        "id": "5a60626f1d41c80c8d3f8a84",
      }
    ]
  }
];

//If you want an array of country objects
console.log([].concat.apply(...(arr || []).map(o=> o.country)))

//If you can an array od country ids
console.log([].concat.apply(...(arr || []).map(o=> o.country.map(country => country.id))))

4 Comments

what if I don't want object, I want pure id in my array?
You mean something like [ '5a60626f1d41c80c8d3f8a85', '5a6062661d41c80c8b2f0413', '5a60626f1d41c80c8d3f8a83', '5a60626f1d41c80c8d3f8a84' ]?
Saw the answer, concat is too confusing, any es6 code?
The reduce answer posted by @nem035 is the ES6 equivalent of this
0

Ayush Gupta's solution will work for this case. But I would like to provide other solution.

const arr = [
  {
    id: 1,
    country: [
      {
        id: '5a60626f1d41c80c8d3f8a85'
      },
      {
        id: '5a6062661d41c80c8b2f0413'
      }
    ]
  },
  {
    id: 2,
    country: [
      {
        id: '5a60626f1d41c80c8d3f8a83'
      },
      {
        id: '5a60626f1d41c80c8d3f8a84'
      }
    ]
  }
];

const ids = arr.reduce(
  (acc, {country}) => [
    ...acc,
    ...country.map(({id}) => ({
      id
    }))
  ],
  []
);
console.log(ids);

1 Comment

what if country's array have other property? I just want to have the id.
0

For JSON string data, it can be done during parsing too :

var ids = [], json = '[{"id":1,"country":[{"id":"5a60626f1d41c80c8d3f8a85"},{"id":"5a6062661d41c80c8b2f0413"}]},{"id":2,"country":[{"id":"5a60626f1d41c80c8d3f8a83"},{"id":"5a60626f1d41c80c8d3f8a84"}]}]';

JSON.parse(json, (k, v) => v.big && ids.push(v));

console.log( ids );

Comments

-1

I am not sure why noone mentioned flat() (probably for large arrays, it might be less performant)

const data=[{id:1,country:[{id:"5a60626f1d41c80c8d3f8a85"},{id:"5a6062661d41c80c8b2f0413"}]},{id:2,country:[{id:"5a60626f1d41c80c8d3f8a83"},{id:"5a60626f1d41c80c8d3f8a84"}]}];

const transformed = (data || []).map(o=>{
  return o.country.map(o2=>({id: o2.id}))
}).flat()

console.log(transformed)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.