0

Given a JS array containing many objects which all contain arrays:

var data = [ 
   {id: 1, name: "Fred", pages:[{url:"www.abc.com", title: "abc"}]}, 
   {id: 2, name: "Wilma", pages:[{url:"www.123.com", title: "123"}]}, 
   {id: 3, name: "Pebbles", pages:[{url:"www.xyz.com", title: "xyz"}]}
];

How do I efficiently extract the inner most array (pages) values into an array?

var dataArray = [
    {url: "www.abc.com", title: "abc"}, 
    {url: "www.123.com", title: "123"}, 
    {url: "www.xyz.com", title: "xyz"}
    ]
4
  • use array map() method. check my answer. Commented Nov 28, 2016 at 6:42
  • What do you mean by "efficiently"? Where are you stuck with this? Do you have a problem with how to loop over data? Do you have a problem with how to retrieve/access the pages property from each element in data? Do you have a problem with how to retrieve/access the first element from each element in pages? Commented Nov 28, 2016 at 6:48
  • Can pages have multiple elements, and if so do you want all of them in the result, or just the first one? Commented Nov 28, 2016 at 6:52
  • Where I was getting stuck is getting url and id from each pages array without knowing the size of the data set. Pages can have any number of elements per array - in this case I only want to return url and title which could be in any order in the pages array. Commented Nov 28, 2016 at 19:31

5 Answers 5

2

The easiest way to do this is to use Array#map like so:

var dataArray = data.map(function(o){return o.pages});

If pages is an array of objects (not a single object), this will result in an array of arrays, which you will need to flatten out for example using Array#reduce:

dataArray = dataArray.reduce(function(a,b){return a.concat(b)}, []); 
Sign up to request clarification or add additional context in comments.

3 Comments

you could combine the two operations like var dataArray = data.map(function(o){return o.pages}).reduce(function(a,b){return a.concat(b)}, []);
I think your reduce is a wordy version of [].concat(...dataArray).
@torazaburo sure that's another way to do it, but uses ... from ES6, ES5 equivalent: Array.prototype.concat.apply([],dataArray)
2

You are looking for a flatMap

var data = [ 
   {id: 1, name: "Fred", pages:[{url:"www.abc.com", title: "abc"}]}, 
   {id: 2, name: "Wilma", pages:[{url:"www.123.com", title: "123"}]}, 
   {id: 3, name: "Pebbles", pages:[{url:"www.xyz.com", title: "xyz"}]}
];

const concat = (xs, ys) => xs.concat(ys);

const prop = x => y => y[x];

const flatMap = (f, xs) => xs.map(f).reduce(concat, []);

console.log(
  flatMap(prop('pages'), data)
);

1 Comment

Very nice except for the missing semicolons.
1

If by "efficiently" you actually mean "concisely", then

[].concat(...data.map(elt => elt.pages))

The data.map will result in an array of pages arrays. The [].concat(... then passes all the pages arrays as parameters to concat, which will combine all of their elements into a single array.

If you are programming in ES5, the equivalent would be

Array.prototype.concat.apply([], data.map(function(elt) { return elt.pages; }))

Comments

1

Here's a working example on how to achieve what you want:

var data = [ 
   {id: 1, name: "Fred", pages:[{url:"www.abc.com", title: "abc"}, {url:"www.google.com", title: "Google"}]}, 
   {id: 2, name: "Wilma", pages:[{url:"www.123.com", title: "123"}]}, 
   {id: 3, name: "Pebbles", pages:[{url:"www.xyz.com", title: "xyz"}]}
];

var arr = Array();
var arr2 = Array();

// You can either iterate it like this:
for (var i = 0; i < data.length; i++) {
  // If you only want the first page in your result, do:
  // arr.push(data[i].pages[0]);

  // If you want all pages in your result, you can iterate the pages too:
  for (var a = 0; a < data[i].pages.length; a++) {
    arr.push(data[i].pages[a]);
  }
}

// Or use the array map method as suggested dtkaias 
// (careful: will only work on arrays, not objects!)
//arr2 = data.map(function (o) { return o.pages[0]; });

// Or, for all pages in the array:
arr2 = [].concat(...data.map(function (o) { return o.pages; }));

console.log(arr);
console.log(arr2);
// Returns 2x [Object { url="www.abc.com",  title="abc"}, Object { url="www.123.com",  title="123"}, Object { url="www.xyz.com",  title="xyz"}]

5 Comments

but it still wrong, what if there will be several page objects in pages key?
That was not the question. The question was how it specifically works with the given array structure. If there are multiple keys, we first need more information on how these should be chained, right?
The pages properties in the input didn't contain multiple objects in the example, but it is "pages" with an "s" and it is an array, so it's not unreasonable to think that sometimes there will be more than one page per id something like pages:[{url:"www.abc.com", title: "abc"}, {url:"www.def.com", title: "def"}, {url:"www.ghi.com", title: "ghi"}]
It's generally considered bad practice to loop over arrays with for...in.
@nnnnnn: But you'll have to agree that this is just an assumption by you as well. The OP explained that she wants a return array with just one object per item. Without further information this code is what does exactly that, even if there are multiple "pages" in the array.
0

use array map() & reduce() method :

var data = [ 
   {id: 1, name: "Fred", pages:[{url:"www.abc.com", title: "abc"}]}, 
   {id: 2, name: "Wilma", pages:[{url:"www.123.com", title: "123"}]}, 
   {id: 3, name: "Pebbles", pages:[{url:"www.xyz.com", title: "xyz"}]}
];
    
var dataArray = data.map(function(item) {
  return item.pages;
});    

dataArray = dataArray.reduce(function(a,b) {
  return a.concat(b);
}, []);

console.log(dataArray);

2 Comments

Yes, but only if the OP wants only the first element in each of the pages array--we'll have to let her tell us if that is the case.
@torazaburo Thanks for correcting me. I updated my answer.

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.