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?
    – user663031
    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?
    – user663031
    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.
    – Veronica
    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)}, []); 
3
  • you could combine the two operations like var dataArray = data.map(function(o){return o.pages}).reduce(function(a,b){return a.concat(b)}, []); Commented Nov 28, 2016 at 2:54
  • I think your reduce is a wordy version of [].concat(...dataArray).
    – user663031
    Commented Nov 28, 2016 at 6:51
  • @torazaburo sure that's another way to do it, but uses ... from ES6, ES5 equivalent: Array.prototype.concat.apply([],dataArray)
    – dtkaias
    Commented Nov 29, 2016 at 0:53
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
  • Very nice except for the missing semicolons.
    – user663031
    Commented Nov 28, 2016 at 11:59
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; }))
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
  • but it still wrong, what if there will be several page objects in pages key?
    – stasovlas
    Commented Nov 28, 2016 at 2:41
  • 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? Commented Nov 28, 2016 at 2:41
  • 1
    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"}]
    – nnnnnn
    Commented Nov 28, 2016 at 3:04
  • It's generally considered bad practice to loop over arrays with for...in.
    – user663031
    Commented Nov 28, 2016 at 6:53
  • @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. Commented Nov 28, 2016 at 21:04
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
  • 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.
    – user663031
    Commented Nov 28, 2016 at 7:01
  • @torazaburo Thanks for correcting me. I updated my answer. Commented Nov 28, 2016 at 8:35

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.