簡體   English   中英

如何在Javascript中動態計算對象值數組?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM