2

我試圖創建一個對象,該對象需要從包含在函數中的四個數組映射 數據。目標 是使用函數式編程完成新地圖。 因此,例如,可以使用方法map,reduce,forEach,concat和 過濾器以及自定義函數。使用函數式編程將多個對象數組中的數據映射到Javascript中的新對象

我已經使用for-loops, 到達了一個非功能性解決方案,我已經在下面列出了它。不過,我陷入了純粹的功能性方法。

想要的結果的數據集和數據可以是 在http://jhusain.github.io/learnrx/處獨立查看,儘管我已經包含了下面的數據。

目標是使用函數式編程重新映射數據,以使其類似於所需的輸出(下面包含)。

我希望幫助重新映射數據使用功能的方法 並從下面顯示的數據開始。

問題的確切的文本規定:

練習26:從數組轉換到更深的樹木

讓我們嘗試創造一個更深層次的樹狀結構。這次我們有4個 分別包含列表,視頻,boxarts和書籤 的單獨陣列。每個對象都有一個父代號,表示它的父代。我們 想要建立一個列表對象的數組,每個列表對象都有一個名字和一個視頻 數組。視頻數組將包含視頻的ID,標題,書籤 時間以及最小的boxart網址。換句話說,我們要建立的 以下結構:

所需的輸出是:

[ 
    { 
     "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" 
      } 
     ] 
    } 
] 

在作爲出發點如下下面的函數。

我已經命名函數「combine」,以便我們可以調用它。另外,我在 函數的末尾添加了我的解決方案,它由for循環組成,位於書籤數組之後。我在一個實用的解決方案只 嘗試了這麼遠:

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. 

這是起始組數據:

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(); 
+0

好像你已經離開做的一切都是'.forEach()'以上您篩選的視頻以及每個視頻的'.forEach()'*(或'.reduce()')*,並通過'boxart'數組找到具有與當前'video.id'匹配的'videoId'的條目。並將其'url'屬性分配給'video.boxart'。然後用'書籤'做同樣的事情。 – 2015-07-10 19:45:07

+0

謝謝。我可能一直過於專注於使用filter()來排除其他方法。 – davisec52

回答

3

這工作,但它不是那麼有效。您首先可以從陣列創建字典或地圖,以便快速查找ID。這將消除對過濾器的需求。

我也避免改變初始數據結構。

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>

+0

好主意不要改變原件。根據'width * height'推送'boxarts'(或其副本),然後使用ES6'.find()'代替'boxart'和'time'的'.filter()',我們會爲了表現而走很遠的路。 – 2015-07-11 00:22:30

2
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 
    }; 
} 
+0

謝謝。在功能編程中真正有用的課程。 – davisec52

0

有由OP鏈接的鍛鍊頁面 「顯示答案」 按鈕。我想答案按鈕沒有在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 }; 
      }); 
     }) 
    }; 
}); 

練習建立在以前的知識,這證明了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在練習10定義,粘貼在這裏爲了方便:

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

    return results; 
}; 

練習說明還指出:「只有更多的一件事:你不能使用索引器。換句話說,這是非法的var itemInArray = movieLists[0];

編輯

從OP的新信息。這似乎是OP想運行演練不行使頁面的上下文,看生產驗證答案它是正確的。要做到這一點,你需要,因爲演習執行略有不同的版本中默認的JavaScript(即filtermapreduceconcatMapconcatAllzip)提供的那些被定義一些額外的功能。如果您使用默認隨着OP的描述,JavaScript版本將會丟失。

爲方便起見,我已經安裝了所需的功能和解決方案,並在jsbin.com記錄了答案控制檯: http://jsbin.com/tolupe/edit?js,console

+0

謝謝你的貢獻!顯示按鈕正在工作,但我已將您在Chrome開發工具中發佈的解決方案與concatAll,concatMap和zip函數一起安裝。該函數返回空數組。從那我認爲答案中有一個錯誤。 – davisec52

+0

@ davisec52不客氣。爲了證明沒有錯誤,我編輯了我的答案,以包含練習的獨立答案。當額外的功能對解決方案不可用時,我能夠複製獲得空數組。 –

+0

感謝您的澄清,並花時間在jsbin上安裝解決方案。我現在看到解決方案確實起作用,並且我假設一個有缺陷的解決方案是不正確的。您的迴應爲整個函數式編程教程提供了清晰和理解。非常感激! – davisec52