1

I have a JavaScript object array with the following structure:

somedata = { foo: { bar: [ { baz: [ { someprop: 'a' }, { someprop: 'b' }, { someprop: 'c' } ] }, { baz: [ { someprop: 'd' }, { someprop: 'e' }, { someprop: 'f' } ] } ] } } 

I want to extract someprop field from this JavaScript object as an array ['a', 'b', 'c', 'd', 'e', 'f']

currently, this is my code logic to extract someprop field as an array:

const result = [] somedata.foo.bar.forEach(x => { x.baz.forEach(y => { result.push(y.someprop) }) }) console.log(result) // prints ["a", "b", "c", "d", "e", "f"] 

i tried to make the code more reusable by creating a function:

function extractToArray(data, arr, prop) { let result = [] data.forEach(x => { x[arr].forEach(y => { result.push(y[prop]) }) }) return result; } console.log(extractToArray(somedata.foo.bar, 'baz', 'someprop')) 

But is there a more concise, elegant, cleaner way to achieve this?


Note:possible duplicate covers an array of objects, but this is regarding an array of objects of an array of objects (so a simple map solution won't work).

5
  • You say a map solution won't work, but it will if you specifically point at the array reference, which is what you're doing currently anyway.
    – zfrisch
    CommentedJul 15, 2019 at 18:53
  • is the object result from a JSON string ?
    – Slai
    CommentedJul 15, 2019 at 18:56
  • i meant to say "a simple map solution" won't work. here is a not-so-simple (imho) map solution that would work: somedata.foo.bar.map(i => i.baz).map(i => i.map(j => j.someprop)).flat()
    – kimbaudi
    CommentedJul 15, 2019 at 18:56
  • @Slai no it is a javascript object, not json
    – kimbaudi
    CommentedJul 15, 2019 at 18:58
  • @kimbaudi Your solution in your most recent comment seems very elegant to me. For the nested structure that you have, you can't really simplify any further.CommentedJul 15, 2019 at 19:00

4 Answers 4

2

You can use flatMap for that:

const somedata = {foo:{bar:[{baz:[{someprop:"a"},{someprop:"b"},{someprop:"c"}]},{baz:[{someprop:"d"},{someprop:"e"},{someprop:"f"}]}]}}; const result = somedata.foo.bar.flatMap(({baz}) => baz.map(({someprop}) => someprop)); console.log(result);

Note that not every current browser supports this yet, so you might want to use a polyfill.

1
  • awesome! this was the solution i was looking for (specifically using flatMap). also +1 for destructuring assignment. This is basically the same solution I ended up with: somedata.foo.bar.flatMap(i => i.baz).flatMap(i => i.someprop)
    – kimbaudi
    CommentedJul 15, 2019 at 19:03
2

You could create recursive function that will find your prop on any level and return array as a result.

const somedata = {"foo":{"bar":[{"baz":[{"someprop":"a"},{"someprop":"b"},{"someprop":"c"}]},{"baz":[{"someprop":"d"},{"someprop":"e"},{"someprop":"f"}]}]}} function get(data, prop) { const result = []; for (let i in data) { if (i == prop) result.push(data[prop]); if (typeof data[i] == 'object') result.push(...get(data[i], prop)) } return result; } console.log(get(somedata, 'someprop'))

1
  • 1
    For the object check, I'd advise looking at the constructor instead of doing typeof. A.e. data[i].constructor.name === "Object" the reason why is because many things(like Arrays) return truthy as an object if you're only looking at typeof.
    – zfrisch
    CommentedJul 15, 2019 at 18:58
1

A recursive function that does it in one functional expression:

const extractToArray = (data, prop) => Object(data) !== data ? [] : Object.values(data).flatMap(v => extractToArray(v, prop)) .concat(prop in data ? data[prop] : []); var somedata = {foo: {bar: [{baz: [{someprop: 'a'},{someprop: 'b'},{someprop: 'c'}]},{baz: [{someprop: 'd'},{someprop: 'e'},{someprop: 'f'}]}]}} console.log(extractToArray(somedata, "someprop"));

This is reusable in the sense that it also works when the property is not always present, or not always at the same depth within the data structure.

1
  • awesome! nice solution using Object.values(data).flatMap
    – kimbaudi
    CommentedJul 15, 2019 at 19:06
1

For others with similar question, I am adding a more generic (but possibly a bit less efficient) alternative using the JSON.parse reviver parameter

var arr = [], obj = {foo:{bar:[{baz:[{someprop:"a"},{someprop:"b"},{someprop:"c"}]},{baz:[{someprop:"d"},{someprop:"e"},{someprop:"f"}]}]}} JSON.parse(JSON.stringify(obj), (k, v) => k === 'someprop' && arr.push(v)) console.log(arr)

0

    Start asking to get answers

    Find the answer to your question by asking.

    Ask question

    Explore related questions

    See similar questions with these tags.