简体   繁体   English

使用函数式编程将数据从多个对象数组映射到Javascript中的新对象

[英]Mapping data from multiple arrays of objects to a new object in Javascript using functional programming

I am trying to create an object that requires mapping data from four arrays included in a function. 我试图创建一个对象,该对象需要从函数中包含的四个数组中映射数据。 The goal is to accomplish the new map using functional programming. 目的是使用功能编程来完成新地图。 Thus, for example, the methods map, reduce, forEach, concat, and filter would be allowed as well as custom functions. 因此,例如,方法,自定义函数,map,reduce,forEach,concat和filter将被允许。

I have arrived at a non functional solution using for-loops, which I've included below. 我已经找到了使用for循环的非功能性解决方案,下面将其介绍给我。 However, I get stuck on a purely functional approach. 但是,我只能使用纯功能方法。

The data set and data for the desired outcome can be viewed independently at http://jhusain.github.io/learnrx/ , though I've included the data below. 可以在http://jhusain.github.io/learnrx/上独立查看所需结果的数据集和数据,尽管我已经在下面提供了数据。

The objective is to re-map the data using functional programming so that it resembles the desired output (included below). 目的是使用功能编程重新映射数据,使其类似于所需的输出(包括在下面)。

I would appreciate help re-mapping the data using a functional approach and starting from the data shown below. 我将不胜感激,可以使用功能性方法并从下面显示的数据开始重新映射数据。

The exact text of the problem states: 问题的确切文本指出:

Exercise 26: Converting from Arrays to Deeper Trees 练习26:从数组转换为更深的树

Let's try creating a deeper tree structure. 让我们尝试创建一个更深的树结构。 This time we have 4 seperate arrays each containing lists, videos, boxarts, and bookmarks respectively. 这次我们有4个单独的数组,每个数组分别包含列表,视频,Boxart和书签。 Each object has a parent id, indicating its parent. 每个对象都有一个父代ID,表示其父代。 We want to build an array of list objects, each with a name and a videos array. 我们要构建一个列表对象数组,每个列表对象都有一个名称和一个视频数组。 The videos array will contain the video's id, title, bookmark time, and smallest boxart url. 视频数组将包含视频的ID,标题,书签时间和最小的Boxart网址。 In other words we want to build the following structure: 换句话说,我们要构建以下结构:

The desired output is: 所需的输出是:

[
    {
        "name": "New Releases",
        "videos": [
            {
                "id": 65432445,
                "title": "The Chamber",
                "time": 32432,
                "boxart": "http://cdn-0.nflximg.com/images/2891/TheChamber130.jpg"
            },
            {
                "id": 675465,
                "title": "Fracture",
                "time": 3534543,
                "boxart": "http://cdn-0.nflximg.com/images/2891/Fracture120.jpg"
            }
        ]
    },
    {
        "name": "Thrillers",
        "videos": [
            {
                "id": 70111470,
                "title": "Die Hard",
                "time": 645243,
                "boxart": "http://cdn-0.nflximg.com/images/2891/DieHard150.jpg"
            },
            {
                "id": 654356453,
                "title": "Bad Boys",
                "time": 984934,
                "boxart": "http://cdn-0.nflximg.com/images/2891/BadBoys140.jpg"
            }
        ]
    }
]

The function that serves as the starting point follows below. 以下是作为起点的功能。

I've named the function "combine" so that we can call it. 我将函数命名为“ combine”,以便我们可以调用它。 Also, I've included my solution, made up of for-loops, at the end of the function after the bookmarks array. 另外,我在书签数组后的函数末尾包含了由for循环组成的解决方案。 My attempt at a functional solution only got this far: 我对功能解决方案的尝试仅此而已:

return lists.map(function(list) {
        return {
            name: list.name,
            videos:
                videos.
                    filter(function(video) {
                        return video.listId === list.id;
                    }).    // I got stuck at this point.

This is the starting set of data: 这是一组初始数据:

function combine() {
    var lists = [
            {
                "id": 5434364,
                "name": "New Releases"
            },
            {
                "id": 65456475,
                name: "Thrillers"
            }
        ],
        videos = [
            {
                "listId": 5434364,
                "id": 65432445,
                "title": "The Chamber"
            },
            {
                "listId": 5434364,
                "id": 675465,
                "title": "Fracture"
            },
            {
                "listId": 65456475,
                "id": 70111470,
                "title": "Die Hard"
            },
            {
                "listId": 65456475,
                "id": 654356453,
                "title": "Bad Boys"
            }
        ],
        boxarts = [
            { videoId: 65432445, width: 130, height:200, url:"http://cdn-0.nflximg.com/images/2891/TheChamber130.jpg" },
            { videoId: 65432445, width: 200, height:200, url:"http://cdn-0.nflximg.com/images/2891/TheChamber200.jpg" },
            { videoId: 675465, width: 200, height:200, url:"http://cdn-0.nflximg.com/images/2891/Fracture200.jpg" },
            { videoId: 675465, width: 120, height:200, url:"http://cdn-0.nflximg.com/images/2891/Fracture120.jpg" },
            { videoId: 675465, width: 300, height:200, url:"http://cdn-0.nflximg.com/images/2891/Fracture300.jpg" },
            { videoId: 70111470, width: 150, height:200, url:"http://cdn-0.nflximg.com/images/2891/DieHard150.jpg" },
            { videoId: 70111470, width: 200, height:200, url:"http://cdn-0.nflximg.com/images/2891/DieHard200.jpg" },
            { videoId: 654356453, width: 200, height:200, url:"http://cdn-0.nflximg.com/images/2891/BadBoys200.jpg" },
            { videoId: 654356453, width: 140, height:200, url:"http://cdn-0.nflximg.com/images/2891/BadBoys140.jpg" }
        ],
        bookmarks = [
            { videoId: 65432445, time: 32432 },
            { videoId: 675465, time: 3534543 },
            { videoId: 70111470, time: 645243 },
            { videoId: 654356453, time: 984934 }
        ];

        //My non-functional solution

    sizeArr = [];

        for(var i = 0; i < lists.length; i++){
            lists[i].videos = [];

            for(var j = 0; j < videos.length; j++){
                if(videos[j].listId === lists[i].id){
                    lists[i].videos.push(videos[j]);

                }
            for(var k = 0; k < bookmarks.length; k++){
                if(bookmarks[k].videoId === videos[j].id && videos[j].listId === lists[i].id){
                    videos[j].time = bookmarks[k].time;
                }

            for(var l = 0; l < boxarts.length; l++){
                var size = boxarts[l].width * boxarts[l].height;
                sizeArr.push(size);
                sizeArr = sizeArr.sort(function(min, max){
                    if(min < max){
                        return min;
                    }

                     if(boxarts[l].videoId === videos[j].id && videos[j].listId === lists[i].id){
                        videos[j].boxart = boxarts[l].url;
                    } 

                });
            }

            }

            }
            delete lists[i].id;
        }

    return lists;
}
combine();

This works, but it's not that efficient. 这可行,但是效率不高。 You first could create dictionaries or maps from your arrays to allow quick id lookups. 首先,您可以从数组中创建字典或映射,以进行快速ID查找。 That would eliminate the need for filters. 这将消除对过滤器的需求。

I also avoided to mutate the initial data structures. 我还避免了更改初始数据结构。

  var lists = [{ "id": 5434364, "name": "New Releases" }, { "id": 65456475, name: "Thrillers" }], videos = [{ "listId": 5434364, "id": 65432445, "title": "The Chamber" }, { "listId": 5434364, "id": 675465, "title": "Fracture" }, { "listId": 65456475, "id": 70111470, "title": "Die Hard" }, { "listId": 65456475, "id": 654356453, "title": "Bad Boys" }], boxarts = [{ videoId: 65432445, width: 130, height: 200, url: "http://cdn-0.nflximg.com/images/2891/TheChamber130.jpg" }, { videoId: 65432445, width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/TheChamber200.jpg" }, { videoId: 675465, width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture200.jpg" }, { videoId: 675465, width: 120, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture120.jpg" }, { videoId: 675465, width: 300, height: 200, url: "http://cdn-0.nflximg.com/images/2891/Fracture300.jpg" }, { videoId: 70111470, width: 150, height: 200, url: "http://cdn-0.nflximg.com/images/2891/DieHard150.jpg" }, { videoId: 70111470, width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/DieHard200.jpg" }, { videoId: 654356453, width: 200, height: 200, url: "http://cdn-0.nflximg.com/images/2891/BadBoys200.jpg" }, { videoId: 654356453, width: 140, height: 200, url: "http://cdn-0.nflximg.com/images/2891/BadBoys140.jpg" }], bookmarks = [{ videoId: 65432445, time: 32432 }, { videoId: 675465, time: 3534543 }, { videoId: 70111470, time: 645243 }, { videoId: 654356453, time: 984934 }]; var videosByList = lists.map(function(list) { return { name: list.name, videos: videos.filter(function(video) { return video.listId == list.id; }).map(function(video) { return { id: video.id, title: video.title, time: bookmarks.filter(function(bookmark) { return bookmark.videoId == video.id; }).pop().time, boxart: boxarts.filter(function(boxart) { return boxart.videoId == video.id; }).sort(function(a, b) { return a.url < b.url ? 1 : (a.url > b.url ? -1 : 0); }).pop().url }; }) }; }); document.querySelector('pre').appendChild(document.createTextNode(JSON.stringify(videosByList, null, 4))) 
 <pre></pre> 

function combine () {

  var Genres = [];

  lists.forEach(function(genre) {
    var currGenre = makeGenre(genre.name, []);

    videos.filter(function(video){
      if (video.listId === genre.id) {
        return video;
      }
    }).forEach(function(video) {

      var time = bookmarks.filter(function(mark){
        if (video.id === mark.videoId) {
          return mark.time;
        }
      })[0];

      var art = boxarts.filter(function(art){
        if (video.id === art.videoId) {
          return art;
        }
      }).sort(function (a, b) { return a.width * a.height > b.width * b.height; })[0];

      currGenre.videos.push(makeVideo(video.id, video.title, time, art));
    });
    Genres.push(currGenre);
  });
  return Genres;
}

function makeGenre (name) {
  return {
    name: name,
    videos: []
  };
}

function makeVideo (id, title, time, boxart) {
  return {
    id: id,
    title: title,
    time: time,
    boxart: boxart
  };
}

There is a "Show Answer" button in the exercise page linked by the OP. OP链接的练习页面中有一个“显示答案”按钮。 I guess the answer button was not working in the OP's chosen browser, so I have pasted the solution here, including extra background information for the exercise: 我猜答案按钮在OP的所选浏览器中不起作用,因此我在此处粘贴了解决方案,包括该练习的其他背景信息:

return lists.map(function(list) {
  return {
    name: list.name,
    videos: 
      videos.
        filter(function(video) {
          return video.listId === list.id;
        }).
        concatMap(function(video) {
          return Array.zip(
            bookmarks.filter(function(bookmark) {
              return bookmark.videoId === video.id;
            }),
            boxarts.filter(function(boxart) {
              return boxart.videoId === video.id;
            }).
        reduce(function(acc,curr) {
              return acc.width * acc.height < curr.width * curr.height ? acc : curr;
            }),
            function(bookmark, boxart) {
              return { id: video.id, title: video.title, time: bookmark.time, boxart: boxart.url };
            });
      })
  };
});

The exercises build on previous knowledge, which demonstrate the concatMap function (see Exercise 13 for the implementation), pasted here for convenience: 这些练习基于先前的知识,这些知识演示了concatMap函数(有关实现,请参见练习13),为方便起见粘贴在此处:

Array.prototype.concatMap = function(projectionFunctionThatReturnsArray) {
  return this.
    map(function(item) {
      return projectionFunctionThatReturnsArray(item);
    }).
    // apply the concatAll function to flatten the two-dimensional array
    concatAll();
};

concatAll is defined in Exercise 10, pasted here for convenience: concatAll在练习10中定义,为方便起见粘贴在此处:

Array.prototype.concatAll = function() {
  var results = [];
  this.forEach(function(subArray) {
    results.push.apply(results, subArray);
  });

  return results;
};

The exercise instructions also dictate: "There's just more one thing: you can't use indexers. In other words, this is illegal var itemInArray = movieLists[0]; " 练习说明还指出:“还有一件事:您不能使用索引器。换句话说,这是非法的var itemInArray = movieLists[0];

Edit 编辑

New information from OP. OP的新信息。 It seems like the OP would like to run the exercise without the context of the exercise page and see the answer produced to verify that it is correct. 好像OP希望在没有练习页面上下文的情况下运行练习,并查看生成的答案以验证它是正确的。 To do this you need some extra functions to be defined because the exercises implement slightly different versions to those supplied by default in JavaScript (ie filter , map , reduce , concatMap , concatAll , zip ). 为此,您需要定义一些额外的函数,因为这些练习实现的版本与JavaScript默认提供的版本略有不同(即filtermapreduceconcatMapconcatAllzip )。 If you use the default JavaScript versions then results go missing as the OP described. 如果您使用默认的JavaScript版本,则结果将如操作说明中所述丢失。

For your convenience, I have setup the required functions and the solution and logged the answer to the console in jsbin.com: http://jsbin.com/tolupe/edit?js,console 为了您的方便,我已经设置了必需的功能和解决方案,并将答案记录在jsbin.com中的控制台上: http ://jsbin.com/tolupe/edit?js,console

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 javascript:如何使用函数式编程比较两个对象数组? - javascript: How to compare two arrays of objects using functional programming? 函数编程方式到javascript对象中的平面数组 - functional programming way to flat arrays in javascript object 如何使用JavaScript函数编程从对象列表中找到属性最低的对象? - How to find the object which has the lowest property from a list of objects using JavaScript functional programming? 使用一些功能编程将一个对象映射到另一个 - mapping one object to another using some functional programming 使用 JavaScript 中的函数式编程将回调应用于 2 个任意长度 arrays - Apply callback to 2 arbitrary length arrays using functional programming in JavaScript 如何从对象数组中检索 object 并使用 javascript 检索 arrays - how to retrieve the object from array of objects and arrays using javascript 将来自 2 arrays 的数据合并到一个新数组中,如 object — Javascript - Merging data from 2 arrays to a new array as object — Javascript 使用函数式编程连接两个JSON对象数组(例如SQL连接) - Joining two arrays of JSON objects like an SQL join using functional programming 从多个嵌套数组创建新数据对象集 - Creating new data object set from multiple nested arrays 使用javascript es6从包含唯一ID和嵌套数组的多个对象数组中获取公共数据 - Get common data from multiple arrays of object that containing a unique id and nested array using javascript es6
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM