John John
John John

Reputation: 1455

JavaScript - map, filter, reduce. Converting from Arrays to Deeper Trees

Each video has an interesting moments collection, each representing a time during which a screenshot is interesting or representative of the title as a whole. Notice that both the boxarts and interestingMoments arrays are located at the same depth in the tree. Retrieve the time of the middle interesting moment and the smallest box art url simultaneously with Array.zip() . Return an {id, title, time, url} object for each video. Anyone can help with Array.zip() ?

const movieLists = [
    {
        name: "New Releases",
        videos: [
            {
                "id": 70111470,
                "title": "Die Hard",
                "boxarts": [
                    { width: 150, height: 200, url: "http://cdn-0.nflximg.com/images/2891/DieHard150.jpg" },
                    { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/DieHard200.jpg" }
                ],
                "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                "rating": 4.0,
                "interestingMoments": [
                    { type: "End", time: 213432 },
                    { type: "Start", time: 64534 },
                    { type: "Middle", time: 323133 }
                ]
            },
            {
                "id": 654356453,
                "title": "Bad Boys",
                "boxarts": [
                    { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/BadBoys200.jpg" },
                    { width: 140, height: 200, url: "http://cdn-0.nflximg.com/images/2891/BadBoys140.jpg" }

                ],
                "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                "rating": 5.0,
                "interestingMoments": [
                    { type: "End", time: 54654754 },
                    { type: "Start", time: 43524243 },
                    { type: "Middle", time: 6575665 }
                ]
            }
        ]
    },
    {
        name: "Instant Queue",
        videos: [
            {
                "id": 65432445,
                "title": "The Chamber",
                "boxarts": [
                    { width: 130, height: 200, url: "http://cdn-0.nflximg.com/images/2891/TheChamber130.jpg" },
                    { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/TheChamber200.jpg" }
                ],
                "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                "rating": 4.0,
                "interestingMoments": [
                    { type: "End", time: 132423 },
                    { type: "Start", time: 54637425 },
                    { type: "Middle", time: 3452343 }
                ]
            },
            {
                "id": 675465,
                "title": "Fracture",
                "boxarts": [
                    { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg" },
                    { width: 120, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture120.jpg" },
                    { width: 300, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg" }
                ],
                "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                "rating": 5.0,
                "interestingMoments": [
                    { type: "End", time: 45632456 },
                    { type: "Start", time: 234534 },
                    { type: "Middle", time: 3453434 }
                ]
            }
        ]
    }
];

Array.zip = function(boxarts, interestingMoments, combinerFunction) {
    let counter,
        results = [];

    for(counter = 0; counter < Math.min(boxarts.length, interestingMoments.length); counter++) {
        results.push(combinerFunction(boxarts[counter],interestingMoments[counter]));
    }

    return results;
};


let arr1 = movieLists.map(function(movieList) {
    return movieList.videos.map(function(video) {
        return Array.zip(
            video.boxarts.reduce(function(acc,curr) {
                if (acc.width * acc.height < curr.width * curr.height) {
                        return acc;
                }
                else {
                      return curr;
                }
              }),
            video.interestingMoments.filter(function(interestingMoment) {
                return interestingMoment.type === "Middle";
            }),
              function(boxart, interestingMoment) {
                return {id: video.id, title: video.title, time: interestingMoment.time, url: boxart.url};
              });
    });
});

// //to enable deep level flatten use recursion with reduce and concat
let concatArr = (function flattenDeep(arr1) {
    return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []);
})(arr1);

console.log(concatArr)

SOLUTION WITHOUT Array.zip() . Anyone can help with Array.zip() ?

let arr1 = movieLists.map(function (movieList) {
    return movieList.videos.map(function (v) {
        return {
            id: v.id,
            title: v.title,
            time: v.interestingMoments
                .reduce(function (accumulator, currentValue) {
                    if (currentValue.type === "Middle") {
                        return accumulator = currentValue
                    }
                }).time,
            url: v.boxarts.reduce((accumulator, currentValue) => {
                var area = currentValue.width * currentValue.height;
                if (area < accumulator.area) {
                    return { area: area, url: currentValue.url };
                }
                return accumulator;
            }, { area: 10000000, url: '' }).url
        }
    });
});

let concatArr = (function flattenDeep(arr1) {
    return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []);
})(arr1);

console.log(concatArr) 

Solution Result enter image description here

SOLUTION with _.zipWith - Lodash

var _ = require('lodash');

    let arr1 = movieLists.map(function(movieList) {
        return movieList.videos.map(function(video) {
            return _.zipWith(
                [video.boxarts.reduce(function(acc,curr) {
                    if (acc.width * acc.height < curr.width * curr.height) {
                            return acc;
                    }
                    else {
                          return curr;
                    }
                  })],
                video.interestingMoments.filter(function(interestingMoment) {
                    return interestingMoment.type === "Middle";
                }),
                  function(boxart, interestingMoment) {
                    return {id: video.id, title: video.title, time: interestingMoment.time, url: boxart.url};
                  });
        });
    });

    //to enable deep level flatten use recursion with reduce and concat
    let concatArr = (function flattenDeep(arr1) {
        return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []);
    })(arr1);

    console.log(concatArr)

Upvotes: 1

Views: 140

Answers (2)

Slai
Slai

Reputation: 22876

Reduced version (pun intended) if JSON.parse is used to get the data:

var result = [], j = '[{"name":"New Releases","videos":[{"id":70111470,"title":"Die Hard","boxarts":[{"width":150,"height":200,"url":"http://cdn-0.nflximg.com/images/2891/DieHard150.jpg"},{"width":200,"height":200,"url":"http://cdn-0.nflximg.com/images/2891/DieHard200.jpg"}],"url":"http://api.netflix.com/catalog/titles/movies/70111470","rating":4,"interestingMoments":[{"type":"End","time":213432},{"type":"Start","time":64534},{"type":"Middle","time":323133}]},{"id":654356453,"title":"Bad Boys","boxarts":[{"width":200,"height":200,"url":"http://cdn-0.nflximg.com/images/2891/BadBoys200.jpg"},{"width":140,"height":200,"url":"http://cdn-0.nflximg.com/images/2891/BadBoys140.jpg"}],"url":"http://api.netflix.com/catalog/titles/movies/70111470","rating":5,"interestingMoments":[{"type":"End","time":54654754},{"type":"Start","time":43524243},{"type":"Middle","time":6575665}]}]},{"name":"Instant Queue","videos":[{"id":65432445,"title":"The Chamber","boxarts":[{"width":130,"height":200,"url":"http://cdn-0.nflximg.com/images/2891/TheChamber130.jpg"},{"width":200,"height":200,"url":"http://cdn-0.nflximg.com/images/2891/TheChamber200.jpg"}],"url":"http://api.netflix.com/catalog/titles/movies/70111470","rating":4,"interestingMoments":[{"type":"End","time":132423},{"type":"Start","time":54637425},{"type":"Middle","time":3452343}]},{"id":675465,"title":"Fracture","boxarts":[{"width":200,"height":200,"url":"http://cdn-0.nflximg.com/images/2891/Fracture200.jpg"},{"width":120,"height":200,"url":"http://cdn-0.nflximg.com/images/2891/Fracture120.jpg"},{"width":300,"height":200,"url":"http://cdn-0.nflximg.com/images/2891/Fracture300.jpg"}],"url":"http://api.netflix.com/catalog/titles/movies/70111470","rating":5,"interestingMoments":[{"type":"End","time":45632456},{"type":"Start","time":234534},{"type":"Middle","time":3453434}]}]}]';

JSON.parse(j, (k, v) => !v.id ? v : result.push({ id: v.id, title: v.title,
  url: v.boxarts.reduce((a, b) => a.width * a.height < b.width * b.height ? a : b).url, 
  time: v.interestingMoments.find(m => m.type === "Middle").time }));

console.log( result );

Upvotes: 1

Jamiec
Jamiec

Reputation: 136104

There is no need for your code to be so complicated. A simple find for the moment, and reduce to determine the largest area will suffice:

var result = movieLists[0].videos.map(v => {
   return {
     id: v.id,
     title: v.title,
     time: v.interestingMoments.find(m => m.type === "Middle").time,
     url: v.boxarts.reduce( (p,c) => {
         var area = c.width*c.height;
         if(area < p.area){
           return {area:area, url: c.url};
         }
         return p;
     },{area:10000000, url:''}).url
   }
});

Live example below:

const movieLists = [
    {
        name: "New Releases",
        videos: [
            {
                "id": 70111470,
                "title": "Die Hard",
                "boxarts": [
                    { width: 150, height: 200, url: "http://cdn-0.nflximg.com/images/2891/DieHard150.jpg" },
                    { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/DieHard200.jpg" }
                ],
                "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                "rating": 4.0,
                "interestingMoments": [
                    { type: "End", time: 213432 },
                    { type: "Start", time: 64534 },
                    { type: "Middle", time: 323133 }
                ]
            },
            {
                "id": 654356453,
                "title": "Bad Boys",
                "boxarts": [
                    { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/BadBoys200.jpg" },
                    { width: 140, height: 200, url: "http://cdn-0.nflximg.com/images/2891/BadBoys140.jpg" }

                ],
                "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                "rating": 5.0,
                "interestingMoments": [
                    { type: "End", time: 54654754 },
                    { type: "Start", time: 43524243 },
                    { type: "Middle", time: 6575665 }
                ]
            }
        ]
    },
    {
        name: "Instant Queue",
        videos: [
            {
                "id": 65432445,
                "title": "The Chamber",
                "boxarts": [
                    { width: 130, height: 200, url: "http://cdn-0.nflximg.com/images/2891/TheChamber130.jpg" },
                    { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/TheChamber200.jpg" }
                ],
                "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                "rating": 4.0,
                "interestingMoments": [
                    { type: "End", time: 132423 },
                    { type: "Start", time: 54637425 },
                    { type: "Middle", time: 3452343 }
                ]
            },
            {
                "id": 675465,
                "title": "Fracture",
                "boxarts": [
                    { width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg" },
                    { width: 120, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture120.jpg" },
                    { width: 300, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg" }
                ],
                "url": "http://api.netflix.com/catalog/titles/movies/70111470",
                "rating": 5.0,
                "interestingMoments": [
                    { type: "End", time: 45632456 },
                    { type: "Start", time: 234534 },
                    { type: "Middle", time: 3453434 }
                ]
            }
        ]
    }
];
var result = movieLists[0].videos.map(v => {
   return {
     id: v.id,
     title: v.title,
     time: v.interestingMoments.find(m => m.type === "Middle").time,
     url: v.boxarts.reduce( (p,c) => {
         var area = c.width*c.height;
         if(area < p.area){
           return {area:area, url: c.url};
         }
         return p;
     },{area:10000000, url:''}).url
   }
});

console.log(result);

Upvotes: 1

Related Questions