[英]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默认提供的版本略有不同(即
filter
, map
, reduce
, concatMap
, concatAll
, zip
)。 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.