Promises in Node js: how to improve? - javascript

I'm working on a coding assignment for node.js and I finished it. However, I am wondering if there is any way to improve upon it. The assignment is to take in 3 promises with JSON objects and merge the data as such.
My code does take in the three promises, resolves them, and merges them according to the specifications. I am worried that the code may be too convoluted.
Are there any recommendations to improve it?
Thanks!
{
travelers: [
id,
name,
flights: [
{
legs: [
{
airlineCode,
airlineName,
flightNumber,
frequentFlyerNumber
}
]
}
]
]
}
As I said, my code works but I'm wondering if it can be improved. Here is my code.
'use strict';
// TODO Import what you need
var tripService = require('./api/trip.service.js');
var profile = require('./api/profiles.service.js');
var airlines = require('./api/airlines.service.js');
function getTravelersFlightInfo() {
var tripServiceGet= () => tripService.get();
var profileGet = () =>profile.get();
var airlinesGet = () => airlines.get();
var trips = tripServiceGet().then(function(trip){
return trip;
});
var profiles = profileGet().then(function(profile){
return profile;
});
var airline = airlinesGet().then(function(airlines){
return airlines;
});
function assignLegsToTraveler(passengerFlight, legs , airline , ff){
passengerFlight = {};
passengerFlight.legs = [];
for(let i = 0; i < legs.length; i++){
var airCode = legs[i].airlineCode;
passengerFlight.legs[i] = {};
passengerFlight.legs[i].airlineCode = airCode;
passengerFlight.legs[i].airlineName = airline.airlines.find( x => x.code === airCode).name;
passengerFlight.legs[i].flightNumber = legs[i].flightNumber;
if (ff.hasOwnProperty(airCode) === true){
passengerFlight.legs[i].frequentFlyerNumber = ff[airCode];
}
}
return passengerFlight;
}
function assignFlights(passenger, trips, airline, ff){
for(let i = 0; i < trips.flights.length; i++){
if(trips.flights[i].travelerIds.includes(passenger.id)){
passenger.flights[passenger.flights.length] = assignLegsToTraveler(passenger.flights[passenger.flights.length], trips.flights[i].legs, airline, ff);
}
}
return passenger;
}
return Promise.all([trips, profiles, airline]).then(function([trips, profiles, airline]) {
var result = {};
result.travelers = [];
for(let i = 0; i < profiles.profiles.length; i++){
result.travelers[i] = {};
result.travelers[i].id = profiles.profiles[i].personId;
result.travelers[i].name = profiles.profiles[i].name;
result.travelers[i].flights = [];
assignFlights(result.travelers[i], trips.trip, airline, profiles.profiles[i].rewardPrograms.air);
}
console.log(JSON.stringify(result, null,2));
return result;
});
}
getTravelersFlightInfo();
module.exports = getTravelersFlightInfo;

Related

applying mulitlevel json to endpoint response

I have the following code deployed as web app on google sheets
function doGet(e){
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/sskey/edit#gid=0");
var sheet = ss.getSheetByName("TV_Series");
return getData(sheet);
}
function getData(sheet){
var jo = {};
var dataArray = [];
var rows = sheet.getRange(2,1,sheet.getLastRow()-1, sheet.getLastColumn()).getValues();
Logger.log("rows = "+rows);
for(var i = 0, l= rows.length; i<l ; i++){
var dataRow = rows[i];
Logger.log("i ="+i);
Logger.log("dataRoes = " +dataRow);
var record = {};
record['series_name'] = dataRow[0];
record['season_name'] = dataRow[1];
record["season_number"] = dataRow[2];
record["episode_name"] = dataRow[3];
record["episode_number"] = dataRow[4];
record["media_url"] = dataRow[8];
dataArray.push(record);
}
jo.series = dataArray;
var result = JSON.stringify(jo);
return ContentService.createTextOutput(result).setMimeType(ContentService.MimeType.JSON);
}
So the web app url returns the following JSON:
{"series":
[{"series_name":"Dance Academy","season_name":"season 3","season_number":"3","episode_name":"Glue","episode_number":"1","media_url":"https://someurl.net/path"},
{"series_name":"Dance Academy","season_name":"season 3","season_number":"3","episode_name":"New Rules","episode_number":"2","media_url":"https://someurl.net/path"}]}
i would like to separate series, seasons, and episodes to different objects in the JSON file. So i will get something like that:
{
"series":{"name": "Dance Academy",
"seasons":
[{"name":"season 1","season_number":1,"episodes":
[{"name":"episode 1","episode_number":1,"url":"https://someurl.net/path"},
{"name":"episode 2","episode_number":2,"url":"https://someurl.net/path"}]},
{"name": "season 2", "season_number":2,"episodes":
[{"name":"episode 1","episode_number":1,"url":"https://someurl.net/path"},
{"name":"episode 2","episode_number":2,"url":"https://someurl.net/path"}]}]}}
How do i do that?
thanks
Description
This assumes there is only one "series". Here is an example script to build a multilevel object from the sample json. You have to build the first object outside of any loop so that you have something to compare with inside the loops.
Code.gs
function testJson() {
try {
let json = {"series":
[{"series_name":"Dance Academy","season_name":"season 3","season_number":"3","episode_name":"Glue","episode_number":"1","media_url":"https://someurl.net/path"},
{"series_name":"Dance Academy","season_name":"season 3","season_number":"3","episode_name":"New Rules","episode_number":"2","media_url":"https://someurl.net/path"}]};
let result = {};
let series = json.series[0];
let name = series.series_name;
result.series = { name: name, seasons: [ { name: series.season_name, season_number: series.season_number, episodes: [] }] };
result.series.seasons[0].episodes.push( { name: series.episode_name, episode_number: series.episode_number, media_url: series.media_url } );
for( let i=1; i<json.series.length; i++ ) {
series = json.series[i];
result.series.seasons.forEach( season => {
if( season.name === series.season_name ) {
season.episodes.push( { name: series.episode_name, episode_number: series.episode_number, media_url: series.media_url } );
}
else {
// add a new season
let j = season.push( { name: series.season_name, season_number: series.season_number, episodes: [] } );
season[j-1].episodes.push( { name: series.episode_name, episode_number: series.episode_number, media_url: series.media_url } );
}
}
);
}
console.log(JSON.stringify(result));
}
catch(err) {
console.log(err);
}
}
Execution log
7:48:56 AM Notice Execution started
7:48:59 AM Info {"series":{"name":"Dance Academy","seasons":[{"name":"season 3","season_number":"3","episodes":[{"name":"Glue","episode_number":"1","media_url":"https://someurl.net/path"},{"name":"New Rules","episode_number":"2","media_url":"https://someurl.net/path"}]}]}}
7:48:57 AM Notice Execution completed

Could someone please explain how to properly write this Javascript function?

I'm looking for someone to show me where I went wrong. The instructions are as follows:
Write the following function (use the songs array to determine what to return).
getSongsNamesByArtist - this function expects a string as an argument
and returns an array containing the names of only those songs in
the songs array whose artist properties are equal to the string
that is passed to it.
So I did this:
let songs = [];
function createSong(name, artist) {
let song = {
name: name,
artist: artist
}
songs.push(song);
return song;
}
var heroes = new createSong("Heroes", "Bowie");
var jubileeStreet = new createSong("Jubilee Street", "Nick Cave");
var buena = new createSong("Buena", "Morphine");
var changes = new createSong("Changes", "Bowie");
var belaLugosi = new createSong("Bela Lugosi is Dead", "Bauhaus");
// I could get only this far:
function getSongsNamesByArtist(artist) {
let names = [];
for (let i = 0; i < songs.length; i++) {
let song = songs[i];
if (song.artist === artist) {
names.push(song.name);
return names;
}
}
}
console.log(getSongsNamesByArtist("Bowie")) // returns: [ 'Heroes' ], but not both of them.
Could you please give me a hint where I went wrong?
Thanks for your time!
The problem is that you are doing an early return in the if statement. So as soon as you are finding a match you return the result.
function getSongsNamesByArtist(artist) {
let names = [];
for (let i = 0; i < songs.length; i++) {
let song = songs[i];
if (song.artist === artist) {
names.push(song.name);
return names; // <- here is your problem
}
}
}
Instead, you want to return after the loop.
function getSongsNamesByArtist(artist) {
let names = [];
for (let i = 0; i < songs.length; i++) {
let song = songs[i];
if (song.artist === artist) {
names.push(song.name);
}
}
return names; // <- here is where you should return
}
You can also consider refactoring this function with the filter and map function in JS
function getSongsNamesByArtist(artist) {
return songs.filter((song) => {
// Filter out the artist you are looking for
return song.artist === artist;
}).map((song) => {
// Reformat your output to only contain the name of the song
return song.name;
});
}
You were returning as soon as first match is found. You have to do it outside for loop . Update your method as below
let songs = [];
function createSong(name, artist) {
let song = {
name: name,
artist: artist
}
songs.push(song);
return song;
}
var heroes = new createSong("Heroes", "Bowie");
var jubileeStreet = new createSong("Jubilee Street", "Nick Cave");
var buena = new createSong("Buena", "Morphine");
var changes = new createSong("Changes", "Bowie");
var belaLugosi = new createSong("Bela Lugosi is Dead", "Bauhaus");
// I could get only this far:
function getSongsNamesByArtist(artist) {
let names = [];
for (let i = 0; i < songs.length; i++) {
let song = songs[i];
if (song.artist === artist) {
names.push(song.name);
}
}
return names;
}
console.log(getSongsNamesByArtist("Bowie"))

JavaScript array has elements but length is zero

I've done some searching around the web and nothing seems to solve my problem. I have the following jQuery code:
function youtube_data_parser(data) {
//---> parse video data - start
var qsToJson = function(qs) {
var res = {};
var pars = qs.split('&');
var kv, k, v;
for (i in pars) {
kv = pars[i].split('=');
k = kv[0];
v = kv[1];
res[k] = decodeURIComponent(v);
}
return res;
}
//---> parse video data - end
var get_video_info = qsToJson(data);
if (get_video_info.status == 'fail') {
return {
status: "error",
code: "invalid_url",
msg: "check your url or video id"
};
} else {
// remapping urls into an array of objects
//--->parse > url_encoded_fmt_stream_map > start
//will get the video urls
var tmp = get_video_info["url_encoded_fmt_stream_map"];
if (tmp) {
tmp = tmp.split(',');
for (i in tmp) {
tmp[i] = qsToJson(tmp[i]);
}
get_video_info["url_encoded_fmt_stream_map"] = tmp;
}
//--->parse > url_encoded_fmt_stream_map > end
//--->parse > player_response > start
var tmp1 = get_video_info["player_response"];
if (tmp1) {
get_video_info["player_response"] = JSON.parse(tmp1);
}
//--->parse > player_response > end
//--->parse > keywords > start
var keywords = get_video_info["keywords"];
if (keywords) {
key_words = keywords.replace(/\+/g, ' ').split(',');
for (i in key_words) {
keywords[i] = qsToJson(key_words[i]);
}
get_video_info["keywords"] = {
all: keywords.replace(/\+/g, ' '),
arr: key_words
};
}
//--->parse > keywords > end
//return data
return {
status: 'success',
raw_data: qsToJson(data),
video_info: get_video_info
};
}
}
function getVideoInfo() {
var get_video_url = $('#ytdlUrl').val();
var get_video_id = getUrlVars(get_video_url)['v'];
var video_arr_final = [];
var ajax_url = "video_info.php?id=" + get_video_id;
$.get(ajax_url, function(d1) {
var data = youtube_data_parser(d1);
var video_data = data.video_info;
var player_info = data.video_info.player_response;
var video_title = player_info.videoDetails.title.replace(/\+/g, ' ');
var fmt_list = video_data.fmt_list.split(',');
var video_thumbnail_url = video_data.thumbnail_url;
var video_arr = video_data.url_encoded_fmt_stream_map;
//create video file array
$.each(video_arr, function(i1, v1) {
var valueToPush = {};
valueToPush.video_url = v1.url;
valueToPush.video_thumbnail_url = video_thumbnail_url;
valueToPush.video_title = video_title;
$.each(fmt_list, function(i2, v2) {
var fmt = v2.split('/');
var fmt_id = fmt[0];
var fmt_quality = fmt[1];
if (fmt_id == v1.itag) {
valueToPush.fmt_id = fmt_id;
valueToPush.fmt_quality = fmt_quality;
}
});
video_arr_final.push(valueToPush);
});
});
return video_arr_final;
}
function getUrlVars(url) {
var vars = {};
var parts = url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) {
vars[key] = value;
});
return vars;
}
function fillInOptions(ytOptions) {
//console.log(ytOptions);
//alert(ytOptions[0]);
var ytFill = ytOptions;
console.log(ytFill);
//ytFill.forEach(function(i,v) {
var ytdlOptions = $('#ytdlOptions');
ytFill.forEach(function(i,v) {
console.log(i);
ytdlOptions.append(new Option(v.fmt_quality, v.fmt_id));
});
return true;
}
function showYTDLLoader() {
$('#ytdlInput').fadeOut(1000, function() {
$('#ytdlLoader').fadeIn(500);
});
var options = getVideoInfo();
//console.log(options);
if (fillInOptions(options) == true) {
//do rest
}
}
function showYTDLOptions() {
return true;
}
function startDownload() {
showYTDLLoader();
}
function hideYTDLLoader() {
$('#ytdlLoader').fadeOut(500);
}
function animateCSS(element, animationName, callback) {
const node = $(element);
node.addClass(animationName);
function handleAnimationEnd() {
node.removeClass(animationName);
node.animationend = null;
if (typeof callback === 'function') callback();
}
node.animationend = handleAnimationEnd();
}
When my button is clicked, I call showYTDLLoader() which gets an array of objects from the YouTube API that looks like this:
[
{
"video_url": "https://r7---sn-uxanug5-cox6.googlevideo.com/videoplayback?expire=1572496003&ei=Iw66Xa24H8PL3LUPiN25mAs&ip=2001%3A8003%3A749b%3Aa01%3A5cd8%3Ac610%3A6402%3Ad0fe&id=o-ADsVnoOoBQ6-SWzYZU7gHES06s7xQptJG6hn9WcakITY&itag=22&source=youtube&requiressl=yes&mm=31%2C29&mn=sn-uxanug5-cox6%2Csn-ntqe6n7r&ms=au%2Crdu&mv=m&mvi=6&pl=39&initcwndbps=1655000&mime=video%2Fmp4&ratebypass=yes&dur=917.768&lmt=1572418007364260&mt=1572474311&fvip=4&fexp=23842630&c=WEB&txp=5535432&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cmime%2Cratebypass%2Cdur%2Clmt&sig=ALgxI2wwRgIhAIp-4gyUTLoXFetbY0ha_YnR7DJqsp_MNjjIxqDdfPZJAiEA_WPd21jgX9broBcigf8rcSEVoJb2_NX7t3XZQqytsSM%3D&lsparams=mm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=AHylml4wRAIgacvP3zjEq-rVEZFrX7a_hC6TR-Zab7Ii-Fbaupjs_PcCIHdZht4l4ioYL3ERz7WNiSbnOnhm5iYxEECaQXPP2hUp",
"video_title": "Arnold Schwarzenegger on Son-in-law Chris Pratt, Pranking Sylvester Stallone & Terminator’s Return",
"fmt_id": "22",
"fmt_quality": "1280x720"
},
{
"video_url": "https://r7---sn-uxanug5-cox6.googlevideo.com/videoplayback?expire=1572496003&ei=Iw66Xa24H8PL3LUPiN25mAs&ip=2001%3A8003%3A749b%3Aa01%3A5cd8%3Ac610%3A6402%3Ad0fe&id=o-ADsVnoOoBQ6-SWzYZU7gHES06s7xQptJG6hn9WcakITY&itag=18&source=youtube&requiressl=yes&mm=31%2C29&mn=sn-uxanug5-cox6%2Csn-ntqe6n7r&ms=au%2Crdu&mv=m&mvi=6&pl=39&initcwndbps=1655000&mime=video%2Fmp4&gir=yes&clen=44248820&ratebypass=yes&dur=917.768&lmt=1572416976690256&mt=1572474311&fvip=4&fexp=23842630&c=WEB&txp=5531432&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cmime%2Cgir%2Cclen%2Cratebypass%2Cdur%2Clmt&sig=ALgxI2wwRQIhANTZJlBHFWQWCnfK11yvLiPUV26c6NzvqIMKjDwmsByMAiBUSy0ZJMo4GdHSiRU4xBDDLxLtzwKZAqAKCiB-1aViDQ%3D%3D&lsparams=mm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=AHylml4wRAIgacvP3zjEq-rVEZFrX7a_hC6TR-Zab7Ii-Fbaupjs_PcCIHdZht4l4ioYL3ERz7WNiSbnOnhm5iYxEECaQXPP2hUp",
"video_title": "Arnold Schwarzenegger on Son-in-law Chris Pratt, Pranking Sylvester Stallone & Terminator’s Return",
"fmt_id": "18",
"fmt_quality": "640x360"
}
]
But when I try and loop through each entry with fillInOptions(), my loop is never completed because the length is apparently zero. However, when I dump the array using console.log() it tells me the length is 2, and displays the above. I need to be able to add each option to my dropdown.
Thankyou!
UPDATE: Added full code, sorry!
It looks like your .forEach() is the root of the problem. The parameters of a forEach are currentValue, index like this: array.forEach(function(currentValue, index) {}); but it looks like you're using them in the opposite way
Try rewriting that iteration to this:
ytFill.forEach(function(v, i) {
console.log(i);
ytdlOptions.append(new Option(v.fmt_quality, v.fmt_id));
});
Notice the difference in the order of v and i in the parameters.

Javascript group URLs by domain and directory

How can I group the URLs from a sorted list by domain and directory?
If two URLs have the same directory (just the first one after domain), then they should be grouped in an array;
Those URLs whose first directory is different, but have the same domain, should be grouped in an array;
For example, the URLs from this list:
var url_list = ["https://www.facebook.com/impression.php/f2e61d9df/?lid=115",
"https://www.facebook.com/plugins/like.php?app_id=5",
"https://www.facebook.com/tr/a/?id=228037074239568",
"https://www.facebook.com/tr/b/?ev=ViewContent",
"http://www.marvel.com/abc?f=33",
"http://www.marvel.com/games?a=11",
"http://www.marvel.com/games?z=22",
"http://www.marvel.com/videos"]
Should be grouped as follows:
var group_url = [
["https://www.facebook.com/impression.php/f2e61d9df/?lid=115","https://www.facebook.com/plugins/like.php?app_id=5",],
["https://www.facebook.com/tr/a/?id=228037074239568","https://www.facebook.com/tr/b/?ev=ViewContent"],
["http://www.marvel.com/abc?f=33","http://www.marvel.com/videos"],
["http://www.marvel.com/games?a=11","http://www.marvel.com/games?z=22"]
]
I wrote some code but only managed to group the URLs by domain:
var group_url = [];
var count = 0;
var url_list = ["https://www.facebook.com/impression.php/f2e61d9df/?lid=115",
"https://www.facebook.com/plugins/like.php?app_id=5",
"https://www.facebook.com/tr/?id=228037074239568",
"https://www.facebook.com/tr/?ev=ViewContent",
"http://www.marvel.com/abc?f=33",
"http://www.marvel.com/games?a=11",
"http://www.marvel.com/games?z=22",
"http://www.marvel.com/videos"]
for(i = 0; i < url_list.length; i++) {
if(url_list[i] != "") {
var current = url_list[i].replace(/.*?:\/\//g, "");
var check = current.substr(0, current.indexOf('/'));
group_url.push([])
for(var j = i; j < url_list.length; j++) {
var add_url = url_list[j];
if(add_url.indexOf(check) != -1) {
group_url[count].push(add_url);
url_list[j] = "";
}
else {
break;
}
}
count += 1;
}
}
console.log(JSON.stringify(group_url));
It seems like you want to group the URLs by domain+dir, but if they end up being alone in their group, to then regroup those by domain only.
For that you can use this script (ES5):
var url_list = ["https://www.facebook.com/impression.php/f2e61d9df/?lid=115",
"https://www.facebook.com/plugins/like.php?app_id=5",
"https://www.facebook.com/tr/a/?id=228037074239568",
"https://www.facebook.com/tr/b/?ev=ViewContent",
"http://www.marvel.com/abc?f=33",
"http://www.marvel.com/games?a=11",
"http://www.marvel.com/games?z=22",
"http://www.marvel.com/videos"];
// Group the URLs, keyed by domain+dir
var hash = url_list.reduce(function (hash, url) {
// ignore protocol, and extract domain and first dir:
var domAndDir = url.replace(/^.*?:\/\//, '').match(/^.*?\..*?\/[^\/?#]*/)[0];
hash[domAndDir] = (hash[domAndDir] || []).concat(url);
return hash;
}, {});
// Regroup URLs by domain only, when they are alone for their domain+dir
Object.keys(hash).forEach(function (domAndDir) {
if (hash[domAndDir].length == 1) {
var domain = domAndDir.match(/.*\//)[0];
hash[domain] = (hash[domain] || []).concat(hash[domAndDir]);
delete hash[domAndDir];
}
});
// Convert hash to array
var result = Object.keys(hash).map(function(key) {
return hash[key];
});
// Output result
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
NB: I did not use ES6 as you mentioned ES5 in comments, but consider using ES6 Map for such a hash, which is better suited for the job.
urllistextended=url_list.map(function(el){return el.split("://")[1].split("/");});//remove protocol, split by /
var obj={};
for(var index in urllistextended){
var el=urllistextended[index];
obj[el[0]]=obj[el[0]]||{};
obj[el[0]][el[1]]=obj[el[0]][el[1]]||[];
obj[el[0]][el[1]].push(url_list[index]);
}
Use like this:
obj["www.facebook.com"];//{plugins:[],tr:[]}
obj["www.facebook.com"]["tr"];//[url1,url2]
http://jsbin.com/qacasexowi/edit?console enter "result"
I would recommend using the excellent URI.js library which offers great ways to parse, query and manipulate URLs: http://medialize.github.io/URI.js/
For example to work with the path (what you are referring to as directory) you could easily do the following (taken straight from the api docs):
var uri = new URI("http://example.org/foo/hello.html");
// get pathname
uri.pathname(); // returns string "/foo/hello.html"
// set pathname
uri.pathname("/foo/hello.html"); // returns the URI instance for chaining
// will encode for you
uri.pathname("/hello world/");
uri.pathname() === "/hello%20world/";
// will decode for you
uri.pathname(true) === "/hello world/";
// will return empty string for empty paths, but:
URI("").path() === "";
URI("/").path() === "/";
URI("http://example.org").path() === "/";
The rest should be easy going.
I suggest to use an object and group by domain and by the first string after the domain. Then iterate the tree and reduce it to the wanted structure.
This solution works with unsorted data.
var url_list = ["https://www.facebook.com/impression.php/f2e61d9df/?lid=115", "https://www.facebook.com/plugins/like.php?app_id=5", "https://www.facebook.com/tr/a/?id=228037074239568", "https://www.facebook.com/tr/b/?ev=ViewContent", "http://www.marvel.com/abc?f=33", "http://www.marvel.com/games?a=11", "http://www.marvel.com/games?z=22", "http://www.marvel.com/videos"],
temp = [],
result;
url_list.forEach(function (a) {
var m = a.match(/.*?:\/\/([^\/]+)\/?([^\/?]+)?/);
m.shift();
m.reduce(function (r, b) {
if (!r[b]) {
r[b] = { _: [] };
r._.push({ name: b, children: r[b]._ });
}
return r[b];
}, this)._.push(a);
}, { _: temp });
result = temp.reduce(function (r, a) {
var top = [],
parts = [];
a.children.forEach(function (b) {
if (b.children.length === 1) {
top.push(b.children[0]);
} else {
parts.push(b.children);
}
});
return top.length ? r.concat([top], parts) : r.concat(parts);
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
This does exactly what you need:
var url_list = ["https://www.facebook.com/impression.php/f2e61d9df/?lid=115",
"https://www.facebook.com/plugins/like.php?app_id=5",
"https://www.facebook.com/tr/a/?id=228037074239568",
"https://www.facebook.com/tr/b/?ev=ViewContent",
"http://www.marvel.com/abc?f=33",
"http://www.marvel.com/games?a=11",
"http://www.marvel.com/games?z=22",
"http://www.marvel.com/videos"];
var folderGroups = {};
for (var i = 0; i < url_list.length; i++) {
var myRegexp = /.*\/\/[^\/]+\/[^\/\?]+/g;
var match = myRegexp.exec(url_list[i]);
var keyForUrl = match[0];
if (folderGroups[keyForUrl] == null) {
folderGroups[keyForUrl] = [];
}
folderGroups[keyForUrl].push(url_list[i]);
}
var toRemove = [];
Object.keys(folderGroups).forEach(function(key,index) {
if (folderGroups[key].length == 1) {
toRemove.push(key);
}
});
for (var i = 0; i < toRemove.length; i++) {
delete folderGroups[toRemove[i]];
}
//console.log(folderGroups);
var domainGroups = {};
for (var i = 0; i < url_list.length; i++) {
//Check if collected previously
var myRegexpPrev = /.*\/\/[^\/]+\/[^\/\?]+/g;
var matchPrev = myRegexpPrev.exec(url_list[i]);
var checkIfPrevSelected = matchPrev[0];
debugger;
if (folderGroups[checkIfPrevSelected] != null) {
continue;
}
//Get for domain group
var myRegexp = /.*\/\/[^\/]+/g;
var match = myRegexp.exec(url_list[i]);
var keyForUrl = match[0];
if (domainGroups[keyForUrl] == null) {
domainGroups[keyForUrl] = [];
}
domainGroups[keyForUrl].push(url_list[i]);
}
//console.log(domainGroups);
var finalResult = {};
$.extend(finalResult, folderGroups, domainGroups);
console.log(Object.values(finalResult));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Filtering an array of Objects in javascript

I'm really new to JS, and I'm now stuck on a task, hope someone can guide me through it.
I have an Array of Objects, like this one:
var labels = [
// labels for pag 1
{pageID:1, labels: [
{labelID:0, content:[{lang:'eng', text:'Txt1 Eng'}, {lang:'de', text:'Txt1 De:'}]},
{labelID:1, content:[{lang:'eng', text:'Txt 2 Eng:'}, {lang:'de', text:'Txt2 De:'}]},
{labelID:2, content:[{lang:'eng', text:'Txt 3 Eng:'},{lang:'de', text:'Txt 3 De:'}]}
]},
// labels for pag 2
{pageID:2, labels: [
{labelID:0, content:[{lang:'eng', text:'Txt1 Eng'}, {lang:'de', text:'Txt1 De:'}]},
{labelID:1, content:[{lang:'eng', text:'Txt 2 Eng:'}, {lang:'de', text:'Txt2 De:'}]},
{labelID:2, content:[{lang:'eng', text:'Txt 3 Eng:'},{lang:'de', text:'Txt 3 De:'}]}
]}
]
What I am trying to do is write a function to return me an array of labels (Objects) for a specific page and a specific lang. By calling this function specifying pageID 1 and lang eng, I'm basically trying to build an array like this one:
var desideredArray = [
{labelID:0, text:'Txt1 Eng'},
{labelID:1, text:'Txt1 Eng'},
{labelID:2, text:'Txt2 Eng'}
]
Now, I'm trying to write the function to retrieve/build the new array:
this.getLabelsForPageAndLang = function (numPage, lang) {
// this part filters the main object and selects the object with pageID == numPage
var result = labels.filter(function( obj ) {
return obj.pageID == numPage;
});
var tempResult = result[0].labels;
var desiredResults = []; // here I want to store the new objects
for (var i=0; i<tempResult.length; i++) {
var simpleLabelObject = {};
simpleLabelObject.labelID = tempResult[i].labelID;
// simpleLabelObject.text = ?????
results[i] = simpleLabelObject;
}
console.log (results);
};
...but how can I access the right value (the one corresponding the lang selected) in the content property?
You can use the same technique as the one used to keep the matching page: the filter method.
this.getLabelsForPageAndLang = function (numPage, lang) {
// this part filters the main object and selects the object with pageID == numPage
var result = labels.filter(function( obj ) {
return obj.pageID == numPage;
});
var contentFilter = function(obj){ return obj.lang === lang};
var tempResult = result[0].labels;
var desiredResults = []; // here I want to store the new objects
for (var i=0; i<tempResult.length; i++) {
var simpleLabelObject = {};
simpleLabelObject.labelID = tempResult[i].labelID;
var matching = tempResult[i].content.filter(contentFilter);
simpleLabelObject.text = matching[0].text;
desiredResults[i] = simpleLabelObject;
}
console.log (desiredResults);
};
I didn't do bound checks because in your code you assumed there is always a matching element, but it would probably be wise to do it.
And if you want to avoid creating two closures each time the function is called, you can prototype an object for that:
var Filter = function(numPage, lang) {
this.numPage = numPage;
this.lang = lang;
};
Filter.prototype.filterPage = function(obj) {
return obj.pageID === this.numPage;
}
Filter.prototype.filterLang = function(obj) {
return obj.lang === this.lang;
}
Filter.prototype.filterLabels = function(labels) {
var result = labels.filter(this.filterPage, this);
var tempResult = result[0].labels;
var desiredResults = []; // here I want to store the new objects
for (var i=0; i<tempResult.length; i++) {
var simpleLabelObject = {};
simpleLabelObject.labelID = tempResult[i].labelID;
var matching = tempResult[i].content.filter(this.filterLang, this);
simpleLabelObject.text = matching[0].text;
desiredResults[i] = simpleLabelObject;
}
return desiredResults;
}
console.log(new Filter(1, "eng").filterLabels(labels));
Just filter again:
var getLabelsForPageAndLang = function (numPage, lang) {
// this part filters the main object and selects the object with pageID == numPage
var result = labels.filter(function (obj) {
return obj.pageID == numPage;
});
var tempResult = result[0].labels;
var desiredResults = []; // here I want to store the new objects
for (var i = 0; i < tempResult.length; i++) {
var simpleLabelObject = {};
simpleLabelObject.labelID = tempResult[i].labelID;
var lg = tempResult[i].content.filter(function (lg) {
return lg.lang == lang;
});
simpleLabelObject.text = lg[0].text;
desiredResults.push(simpleLabelObject);
}
console.log(desiredResults);
};
http://jsfiddle.net/9q5zF/
A rather 'safe' implementation for cases when pages have the same pageID and multiple contents with the same lang:
this.getLabelsForPageAndLang = function(numPage, lang) {
var result = [];
var pages = labels.filter(function( obj ) {
return obj.pageID === numPage;
});
for (var p = pages.length - 1; p >= 0; p--) {
var page = pages[p];
for(var i = page.labels.length - 1; i >= 0; i--) {
var labelId = page.labels[i].labelID;
for (var j = page.labels[i].content.length - 1; j >= 0; j--){
if (page.labels[i].content[j].lang === lang) {
result.push({labelID: labelId, test: page.labels[i].content[j].text});
}
}
}
}
console.log(result);
}
Fiddle: http://jsfiddle.net/6VQUm/

Categories

Resources