[英]How to dynamically calculate the array of object values in Javascript?
我的輸入格式如下,
var boxplotInput = [{Day: "01-07-2021", "Thomas": 95, "Diana": 94, "Claura": 93, "Chandler": 93},
{Day: "02-07-2021", "Thomas": 95, "Diana": 94, "Claura": 94, "Chandler": 94},
...
...
{Day: "31-07-2021", "Thomas": 92, "Diana": 94, "Claura": 93, "Chandler": 91}];
我對javascript對象處理很陌生。 我編寫了如下代碼來計算 Q1、Q3 和中位數,它在數學上按我預期的方式運行良好。
//Getting the list of students (excluding date)
var keys;
for(var i = 0; i <boxplotInput.length; i++ ){
keys = Object.keys(boxplotInput[i]).slice(1);
}
////Here, I am hard-coding keys[0]. and getting "Thomas" data only. I am not getting how to avoid for one students only and achieve it for all students.
var studentDataSample = [];
for(var i = 0; i <boxplotInput.length; i++ ){
student1 = boxplotInput[i][keys[0]];
studentDataSample.push(student1);
}
studentDataSample.sort(function(a, b) {return a - b;});
var length = studentDataSample.length;//31
var midIndex = middleIndex(studentDataSample, 0, length);//16
var medianValue = studentDataSample[midIndex];
var Q1 = studentDataSample[middleIndex(studentDataSample, 0, midIndex)];
var Q3 = studentDataSample[middleIndex(studentDataSample, midIndex + 1, length)];
console.log(Q1+", "+medianValue+", "+Q3);// here, the values are fine.
function middleIndex(data, initial, length){
var n = length - initial + 1;
n = parseInt((n + 1) / 2);
return parseInt(n + initial);
}
有些東西,我知道它可以通過循環再次實現..但是,沒有得到如何為所有學生實現它。 請提供關於此的建議或想法。
提前致謝。
如果我理解正確,您都需要以下 JS 方法:
您在這里需要的主要內容是創建有用的學生集合及其成績。 在此之后,您可以計算所有您想要的東西。 在這個例子中,我展示了如何計算平均值。
var boxplotInput = [ {Day: "01-07-2021", "Thomas": 95, "Diana": 94, "Claura": 93, "Chandler": 93}, {Day: "02-07-2021", "Thomas": 95, "Diana": 94, "Claura": 94, "Chandler": 94}, {Day: "31-07-2021", "Thomas": 92, "Diana": 94, "Claura": 93, "Chandler": 91} ]; /* Get collection of students like: { Thomas: [ 95, 95, 92 ], Diana: [ 94, 94, 94 ], Claura: [ 93, 94, 93 ], Chandler: [ 93, 94, 91 ] } */ const students = boxplotInput.reduce((accumulator, currentDay) => { const students = Object .keys(currentDay) .filter(el => el !== 'Day'); students.forEach(student => { if (!accumulator[student]) { accumulator[student] = []; } accumulator[student].push(currentDay[student]); }); return accumulator; }, {}); console.log('Student grades:', students); // Then we can do anything with it const studentNames = Object.keys(students); // Example: finding mean const studentMeans = studentNames.reduce((acc, student) => { const grades = students[student]; const sumOfGrades = grades.reduce((acc, cur) => cur + acc, 0); acc[student] = sumOfGrades / grades.length; return acc; }, {}); console.log('Means:', studentMeans); /* { Thomas: 94, Diana: 94, Claura: 93.33333333333333, Chandler: 92.66666666666667 } */
我將向您展示使用 Underscore 的一種非常簡潔的方法。 讓我們檢查一下 Underscore 和 JavaScript 為此目的提供的所有工具,並一步一步構建我們的解決方案。
Underscore 的一個不錯的功能是chain
,它可以讓我們逐步以不同的形狀處理數據,同時保持代碼非常易於閱讀。 例如,您可能會猜到以下鏈會做什么:
var sortedLast = _.chain([2, 3, 1]) .sort() .last(); console.log(sortedLast);
<script src="https://underscorejs.org/underscore-umd-min.js"></script>
chain
在輸入數據周圍創建了一個特殊的包裝器,它具有所有下划線函數作為方法。 每個方法都返回一個新的包裝器,因此您可以繼續應用更多的下划線函數。 最后,您可以通過調用.value()
來解開結果。 在某些情況下,例如上面的示例,這會自動發生。 last
返回數組的最后一個元素。
我們可能想要努力的一個很好的最終形狀可能如下:
{
Thomas: {min: 92, Q1: 93.5, median: 95, Q3: 95, max: 95},
Diana: {min: 94, Q1: 94, median: 94, Q3: 94, max: 94},
Claura: {min: 93, Q1: 93, median: 93, Q3: 93.5, max: 94},
Chandler: {min: 91, Q1: 92, median: 93, Q3: 93.5, max: 94},
}
這是一個與boxplotInput
的每個元素具有相同鍵的對象,除了Day
。 Underscore 有一個omit
函數,它可以讓我們干凈利落地完成這項工作,而不必依賴以特定順序出現的鍵:
_.chain(boxplotInput[0])
.omit('Day');
// {Thomas: 95, Diana: 94, Claura: 93, Chandler: 93}
現在我們有了一個具有正確鍵但值錯誤的對象。
mapObject
讓我們創建一個具有相同鍵但不同值的新對象。 除了輸入對象之外,它還需要一個函數,該函數將依次應用於輸入對象的每個鍵值對。 該函數將值作為第一個參數,將鍵作為第二個參數。 它的返回值成為新對象中對應鍵的值。
作為中間步驟,讓我們創建一個包含每個學生所有分數列表的對象:
{
Thomas: [95, 95, 92],
Diana: [94, 94, 94],
Claura: [93, 94, 93],
Chandler: [93, 94, 91],
}
為了用mapObject
實現這一點,我們需要編寫一個函數,給定一個學生的名字,返回一個包含學生分數的數組。 它的開始看起來像這樣:
function studentScores(firstScore, studentName) {
// code here
}
讓我們看一個獲得這些分數的優雅方法。 在您的原始代碼中,您編寫了類似這樣的內容(但使用key[0]
而不是studentName
):
var studentDataSample = [];
for (var i = 0; i < boxplotInput.length; i++) {
var student1 = boxplotInput[i][studentName];
studentDataSample.push(student1);
}
下划線可讓您使用map
在很短的一行中獲得相同的結果:
var studentDataSample = _.map(boxplotInput, studentName);
現在 JavaScript 的數組有一個內置的map
方法,可以讓你做類似的事情。 它不如 Underscore 的map
靈活簡潔,但我將展示如何使用它以確保完整性:
var studentDataSample = boxplotInput.map(dayScores => dayScores[studentName]);
我們現在知道如何編寫studentScores
:
function studentScores(firstScore, studentName) {
return _.map(boxplotInput, studentName);
}
我們不需要firstScore
,但無論如何我們都必須接受它作為第一個參數,因為我們要將此函數傳遞給mapObject
,它總是首先傳遞值。 幸運的是,我們可以忽略它。 我們可以使用新的箭頭符號更簡潔地編寫這個函數:
(fs, studentName) => _.map(boxplotInput, studentName)
現在我們可以在我們的鏈中包含這個函數,以獲得我們之前討論過的中間結果:
_.chain(boxplotInput[0])
.omit('Day')
.mapObject((fs, studentName) => _.map(boxplotInput, studentName));
// {
// Thomas: [95, 95, 92],
// Diana: [94, 94, 94],
// Claura: [93, 94, 93],
// Chandler: [93, 94, 91]
// }
讓我們也對分數進行排序,為計算分位數做准備:
_.chain(boxplotInput[0])
.omit('Day')
.mapObject((fs, studentName) => _.map(boxplotInput, studentName).sort());
// {
// Thomas: [92, 95, 95],
// Diana: [94, 94, 94],
// Claura: [93, 93, 94],
// Chandler: [91, 93, 94]
// }
我們可以將另一個mapObject
添加到鏈中,以便將這些排序分數數組轉換為我們目標的最終{min, Q1, median, Q3, max}
對象。 由於這不是您的問題的真正含義,因此我將提出一種可能的方法來以功能樣式進行操作:
// A function that returns a function (this is not a typo) that // computes a particular quantile from a sorted array of numbers. function quantile(fraction) { return function(numbers) { var middle = (numbers.length - 1) * fraction; return (numbers[Math.floor(middle)] + numbers[Math.ceil(middle)]) / 2; }; } // A "blueprint" object with the keys we want to have, each having a // function to compute the corresponding value from a sorted array of // scores. var quantileComputations = { min: _.first, Q1: quantile(.25), median: quantile(.5), Q3: quantile(.75), max: _.last, }; // A function that applies the above blueprint to a given array of // numbers. function getQuantiles(numbers) { return _.mapObject(quantileComputations, f => f(numbers)); } // Redefining the input data to make this snippet runnable. var boxplotInput = [ {Day: "01-07-2021", "Thomas": 95, "Diana": 94, "Claura": 93, "Chandler": 93}, {Day: "02-07-2021", "Thomas": 95, "Diana": 94, "Claura": 94, "Chandler": 94}, {Day: "31-07-2021", "Thomas": 92, "Diana": 94, "Claura": 93, "Chandler": 91}, ]; // Completing our chain using the above. var statistics = _.chain(boxplotInput[0]) .omit('Day') .mapObject((fs, studentName) => _.map(boxplotInput, studentName).sort()) .mapObject(getQuantiles) .value(); console.log(statistics);
<script src="https://underscorejs.org/underscore-umd-min.js"></script>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.