Reputation: 339
Using Wikipedia's API I got an object which looks like that:
obj = {["string", Array[10], Array[10], Array[10]]}
The first array contains titles, second is descriptions and third is links.
Some of the descriptions may be empty ("").
Example -
I would like to combine all three arrays into one array as follow:
[{title: obj[1][0], desc: obj[2][0], link: obj[3][0]}, ... , {title: array[1][9], desc: obj[2][0], link: obj[3][0]}]
But only combining if description is not empty - obj[2][i] !== ""
I managed to do it using for loop and if:
var arr = [];
for (var i = 0; i < data[1].length; i++) {
if (data[2][i] !== '') {
arr.push({title: data[1][i], desc:data[2][i], link: data[3][i]});
}
}
Is there a way of achieving the same in a more elegant way using javascript's high order function? such as map
and filter
(maybe reduce
?)
Thanks
EDIT:
The way I did it in the end was:
var resp = ["Football",
['Football', 'Soccer'],
['FootballDescription', 'SoccerDescription'],
['http://football.com', 'http://soccer.com']
];
// Mimic python's zip behavior -> assume arrays are of equal size
function zip(arrays) {
return arrays[0].map(function(_, i){
return arrays.map(function(array){
return array[i];
});
});
}
// 1. Throw away the first string, e.g. "Football"
resp.shift();
// 2. Use zip to make an array of intersected arrays, i.e
// [
// ['Football', 'FootballDescription', 'http://football.com'],
// ['Soccer', 'SoccerDescription', 'http://soccer.com']
// ]
// and then use map to make each array into a nicely named object
var objects = zip(resp).map(function(x) {
return ({ name: x[0], desc: x[1], link: x[2] });
});
console.log(objects);
/*
Output:
[ { name: 'Football',
description: 'FootballDescription',
link: 'http://football.com' },
{ name: 'Soccer',
description: 'SoccerDescription',
link: 'http://soccer.com' } ]
*/
Upvotes: 1
Views: 4101
Reputation: 1074
You're about to learn an awesome new higher-order function, zip! To be honest, I very rarely run into situtations where it is useful, but your example happens to be perfect for it.
/*
Example in ES6. In order to run, first install node and then go
npm install -g babel
npm install underscore
babel thisfile.js | node
*/
let _ = require('underscore')
let resp = [
"Football",
['Football', 'Soccer'],
['FootballDescription', 'SoccerDescription'],
['http://football.com', 'http://soccer.com']
]
// 1. Throw away the first string, e.g. "Football"
resp.shift()
// 2. Use zip to make an array of intersected arrays, i.e
// [
// ['Football', 'FootballDescription', 'http://football.com'],
// ['Soccer', 'SoccerDescription', 'http://soccer.com']
// ]
// and then use map to make each array into a nicely named object
let objects = _.zip(
resp[0],
resp[1],
resp[2]
).map(x => ({
name: x[0],
desc: x[1],
link: x[2]
}))
console.log(objects)
/*
Output:
[ { name: 'Football',
description: 'FootballDescription',
link: 'http://football.com' },
{ name: 'Soccer',
description: 'SoccerDescription',
link: 'http://soccer.com' } ]
*/
Upvotes: 3
Reputation: 493
There's no need to involve another library if you don't want. Map and filter work here but I think they add a lot of length. I'd favor forEach.
Keep in mind that Array.prototype.forEach passes along up to three parameters to your callback function. In this case you can get by with two.
data[2].forEach(function(elem, index) {
elem && arr.push({title: data[1][index], desc: elem, link: data[3][index]});
});
And a solution using map and filter might look like
data[1].map(function(elem, index) {
return ({
title: data[1][index],
description: data[2][index],
link: data[3][index]
});
}).filter(function(elem) {
return elem.description;
});
Upvotes: 2
Reputation: 200
Looks like you need some lodash/underscore in your life…
http://underscorejs.org/ https://lodash.com/
They are libraries that do exactly that. Take Objects/Arrays and slice and dice them until they are what you want. Super useful.
Or you could just do it in plain ol' reduce…
var crazyArray = ['title here', ['one', 'two', 'three'], ['four', 'five'], '', ['six']]
var reduced = crazyArray.reduce(function( last, cur ){
if(cur) return last.concat(cur);
return last;
}, []);
console.log(reduced) // [ 'title here', 'one', 'two', 'three', 'four', 'five', 'six' ]
Upvotes: 1