How group students with different scores in leveled groups - javascript

I need to create groups of students to work together, but i need to level the groups using his grades. So, i don't want only the good grades students in one hand and the bad grades on other. I want to mix them all using his grades to randomize that.
So, i have the name and the score for every student. I need 3 homework groups, so i calculated the score of all / 3. To know the value who every single group need.
Now it's the problem, i don't know how can i insert the students in this groups without be over the max value for one group and how guarantee every group with same number of students.
Until now, i make this:
var totalScore = 0;
for (var i = 0; i < students.length; i++) {
totalScore = totalScore + students[i].score;
}
var maxScoreForGroup = totalScore / 3;
console.log(maxScoreForGroup);
for (var o = 0 ; o < students.length; o++) {
if ((students[o].score + homeWork1[0].scoreTotal) < maxScoreForGroup) {
homeWork1[0].students.push(students[o].name);
homeWork1[0].scoreTotal = homeWork1[0].scoreTotal + students[o].score;
} else if ((students[o].score + homeWork2[0].scoreTotal) < maxScoreForGroup) {
homeWork2[0].students.push(students[o].name);
homeWork2[0].scoreTotal = homeWork2[0].scoreTotal + students[o].score;
} else {
homeWork3[0].students.push(students[o].name);
homeWork3[0].scoreTotal = homeWork3[0].scoreTotal + students[o].score;
}
}
But i'm getting in homeWork1 only 2 students with score 10 each, in homework2 only 2 students with score 10 and 7.5, and in homework 3 every other student.
How can i change this to get 3 groups with 3 students and every group with the same score total?
My array of students
var students = [
{
"name": "Charles",
"score": 10
},
{
"name": "Max",
"score": 10
},
{
"name": "Samuel",
"score": 10
},
{
"name": "Carl",
"score": 7.5
},
{
"name": "James",
"score": 7.5
},
{
"name": "Frank",
"score": 7.5
},
{
"name": "George",
"score": 5
},
{
"name": "Timothy",
"score": 5
},
{
"name": "Paul",
"score": 5
},
]
My output is
"[{"scoreTotal":20,"students":["Charles","Max"]}]"
"[{"scoreTotal":17.5,"students":["Samuel","Carl"]}]"
"[{"scoreTotal":30,"students":["James","Frank","George","Timothy","Paul"]}]"
I made this fiddle too

Here's another approach that might work for you.
We shuffle the students array, split into groups of n students (in this case 3), then get the total scores of each group.
If the groups have the same total score we add to our possibleGroups array.
You can change the number of attempts or just repeat to get different groupings.
const students = [ { "name": "Charles", "score": 10 }, { "name": "Max", "score": 10 }, { "name": "Samuel", "score": 10 }, { "name": "Carl", "score": 7.5 }, { "name": "James", "score": 7.5 }, { "name": "Frank", "score": 7.5 }, { "name": "George", "score": 5 }, { "name": "Timothy", "score": 5 }, { "name": "Paul", "score": 5 }, ]
function shuffle(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
}
function getTotalScore(a) {
return a.reduce((total, student) => total + student.score, 0);
}
function allEqual(a) {
return (new Set(a).size) === 1;
}
function split(a, groupSize) {
return a.reduce((sums, x, idx) => {
if (idx % groupSize === 0) {
sums.push([]);
}
sums[sums.length - 1].push(x);
return sums;
}, [])
}
let attempts = 20;
let n = 3;
let possibleGroups = [];
for(let i = 0; i < attempts; i++) {
let groups = split(shuffle([...students]), n);
let scores = groups.map(getTotalScore);
if (allEqual(scores)) {
possibleGroups.push( { scoreTotal: scores[0], groups } );
}
}
console.log('Possible groupings:');
possibleGroups.forEach((group, idx) => {
console.log(`Grouping ${idx + 1}:`);
console.log(JSON.stringify(group, null, 2))
})
.as-console-wrapper { max-height: 100% !important; }

Related

Remove Object if Key Value don't match Input Variable after calculating and comparing with input variables

I am trying to compare input variable key/values with data in Json file, there are 200+ orders in the file, for Order_number (66 in this case) need to calculate and compare the count of line items(6 in this case) along with the Quantity of items(7 in this case), if it doesn't match need to remove Object Refund along with its elements, else leave it as it is.
The variables from the sql query result to be compared against this sample would be :
Order_number 66
count of line items 6
Quantity of items 6
I got stuck at calculating it.
File Content:
{
"app_id": 111,
"fulfillments": [],
"line_items": [
{
"id": 376,
"quantity": 2
},
{
"id": 992,
"quantity": 1
},
{
"id": 929,
"quantity": 1
},
{
"id": 768,
"quantity": 1
},
{
"id": 929,
"quantity": 1
},
{
"id": 768,
"quantity": 1
}
],
"name": "#59",
"number": 6,
"order_number": 66,
"order_id": 999,
]
}
var derivedOrderNumber = getVariable("Trans_ID", "");
var derivedNumberOfLineItems = getVariable("Count_Of_Fulfillment", "");
var derivedTotalQuantityOfItems = getVariable("Total_Quantity", "");
var jsonOrderNumber = 0;
var jsonNumberOfLineItems = 0;
var jsonTotalQuantityOfItems = 0;
//Calculate Number of Line Items and Total Quantity for order_number
let output = arr.reduce((op,cur)=>{
if(op[cur['ORDER_NUMBER']]){
op[cur['LINE_ITEMS']]['jsonTotalQuantityOfItems']+=cur['QUANTITY'];
op[cur['LINE_ITEMS']]['jsonNumberOfLineItems']++;
} else {
op[cur['ORDER_NUMBER']] ={
'jsonNumberOfLineItems' : 1,
'jsonTotalQuantityOfItems' : cur['QUANTITY'],
}
}
return op;
},{})
console.log(output);
try this
let arrSum = 0;
data.line_items.forEach((element) => {
arrSum += element.quantity;
});
if (arrSum != data.number) delete data.refunds;

subtract Object value into array is not correct

l am trying to sum total price from array object then add the total price outside that array.
example :
[
{
"addons": [
{
"title": "خبز بعجين",
"price": 0.1,
"selected": true
},
{
"title": "لحم بعجين ",
"price": 2,
"selected": true
},
{
"title": "ببسي بارد",
"price": 55,
"selected": true
},
{
"title": "كولا ",
"price": 4,
"selected": true
}
],
"Totaladdons": 61.1, // < total price of array above .
"price" : 300 // < sum Totaladdons with this object price .
}
]
sum(data) {
let totalPrice = 0;
let currency: any
currency = this.items_local[data.index].addons.map(curr => parseFloat(curr.price)).reduce((a, b) => a + b, 0)
console.log(currency);
this.items_local[data.index].Totaladdons = Number(currency);
if (this.items_local[data.index].Totaladdons) {
totalPrice = Number(this.items_local[data.index].Totaladdons) + Number(this.items_local[data.index].price)
this.items_local[data.index].price = totalPrice.toFixed(2)
}
}
Minus method to remove element array object then resuming total price
minus(data) {
if (this.items_local[data.index].addons.length > 0) {
for (var i = this.items_local[data.index].addons.length - 1; i >= 0; i--) {
if (this.items_local[data.index].addons[i].title === data.addon.title) {
this.items_local[data.index].addons.splice([i], 1);
// here l am try to resuming the price of array object
currency = this.items_local[data.index].addons.map(curr => parseFloat(curr.price)).reduce((a, b,) => a - b, 0);
console.log(currency);
if (this.items_local[data.index].Totaladdons) {
this.items_local[data.index].Totaladdons = Number(currency);
totalPrice = Number(this.items_local[data.index].price) - Number(this.items_local[data.index].Totaladdons)
this.items_local[data.index].price = totalPrice.toFixed(2)
}
}
}
}
}
The problem is when l click on the minus method he is not giving me the correct total number.

For loop with Javascript to get values

I have this variable named: var quantity.
This variable changes continuously. For example: quantity = 1, quantity = 26...
On the other hand I have an array of elements with prices according to the quantity of the product: var quantity_prices.
var quantity_prices = [
{
"quantity": 1,
"price_pvp": 7.96
}, {
"quantity": 5,
"price_pvp": 7.96
}, {
"quantity": 15,
"price_pvp": 6.97
}, {
"quantity": 25,
"price_pvp": 5.97
}
];
I want to make that if quantity is between quantities 1 and 5, 6 and 14, 15 and 24, the product has the right price.
Example:
if the quantity is 16, the price I want to take is: 5,95€.
I've thought about using a for loop but I don't know how to continue to make this work what I want to do:
for (var i = 0; i < this.quantity_prices.length; i++) { // if quantity is between 1 and 5
new_price = this.quantity_prices[i].price_pvp;
// elseif quantity is between 6 and 14
new_price = this.quantity_prices[i].price_pvp;
// elseif quantity is between 15 and 24
new_price = this.quantity_prices[i].price_pvp;
}
var quantity_prices = [
{
"quantity": 1,
"price_pvp": 7.96,
},
{
"quantity": 5,
"price_pvp": 7.96,
},
{
"quantity": 15,
"price_pvp": 6.97,
},
{
"quantity": 25,
"price_pvp": 5.97,
}
];
for(let i=0;i<quantity_prices.length;i++){
if(quantity_prices[i].quantity>0 && quantity_prices[i].quantity<5 )
{
//whatever the required output you want.
quantity_prices[i].new_price=quantity_prices[i].price_pvp;
}if(quantity_prices[i].quantity>6 && quantity_prices[i].quantity<14){
}
if(quantity_prices[i].quantity>15 && quantity_prices[i].quantity<24){
}
}
console.log(quantity_prices)
Here try it with this:
function check(){
this.quantity_prices.find(({price}) => {
if(price_pvp > 1 && price_pvp < 5){
// do something
}
if(price_pvp > 6 && price_pvp < 14){
// do something
}
if(price_pvp > 15 && price_pvp < 24){
// do something
}
}
}
You can group according to your req as per below code and then print the price.
var quantity_prices = [{
"quantity": 1,
"price_pvp": 7.96,
},
{
"quantity": 5,
"price_pvp": 7.96,
},
{
"quantity": 15,
"price_pvp": 6.97,
},
{
"quantity": 25,
"price_pvp": 5.97,
}
];
var group1_5 = quantity_prices.filter(q => q.quantity >= 1 && q.quantity <= 5);
console.log(group1_5);
//print your price
if (group1_5.length > 0) {
console.log(group1_5[0].price_pvp)
}
var group6_16 = quantity_prices.filter(q => q.quantity >= 6 && q.quantity <= 14);
console.log(group6_16);
You can search for the right quantity, then return the price for this amount.
I'm assuming that if the quantity is not found directly we'll return the next entry in the quantity / price table.
const quantity_prices = [ { "quantity": 1, "price_pvp": 7.96, }, { "quantity": 5, "price_pvp": 7.96, }, { "quantity": 15, "price_pvp": 6.97, }, { "quantity": 25, "price_pvp": 5.97, } ];
function getPrice(quantity, priceLookup) {
let entry = priceLookup.find((e,index) => e.quantity >= quantity || index === priceLookup.length-1);
return entry.price_pvp;
}
console.log("Price table:");
const quantities = [1,4,5,10,15,16,25,26,30];
for(let quantity of quantities ) {
console.log(`Price (${quantity }): €${getPrice(quantity, quantity_prices)}`);
}

Comparing information from an API call and an Array

I'm trying to compare the results of an API call to an existing array. Basically, I want to make a function that will loop through the array, then loop through the data from the API to see if there's a match.
Here's an example of the array I'm working with
let array = [ {
"name": "student1",
"id": 134},
{
"name": "student2",
"id": 135},
{
"name": "student3",
"id": 136}
]
Here's my function in JavaScript/jQuery
function getData() {
$.ajax({
url: "www.studentapi.com",
dataType: "json"
}).done(function(data) {
console.log(data)
}
}
The data I get back looks kind of like this:
[ {
"id": 134,
"score": 45},
{
"id": 138,
"score": 67},
{
"id": 139,
"score": 34}
]
I'm trying to find a way to find the matching ids in the array and in the data. So far I've tried:
for (let j =0; j < data.length; j++) {
if (array[j]["id"] === data[j].id) {
console.log("we have a match!")
}
else {
console.log("not a match!");
}
}
But this isn't working. Am I doing something incorrectly over here?
You can use find on an array to find an element that matches some conditional.
The below logic also uses arrow functions, but could be changed to use normal function(){}
let array = [
{
"name": "student1",
"id": 134
},
{
"name": "student2",
"id": 135
},
{
"name": "student3",
"id": 136
}
];
let data = [
{
"id": 134,
"score": 45
},
{
"id": 138,
"score": 67
},
{
"id": 139,
"score": 34
}
];
let studentData = array.map(student=>{
student.data = data.find(record=>record.id === student.id) || {};
return student;
});
console.log(studentData);
I would use the javascript filter function.
let matchingStudents = array.filter(student => {
return data.find(jsonData => student.id === jsonData.id);
});
There matchingStudents would hold all students present in the first array that are present in the second.
If you are wondering about the syntax, this is ES6. Next generation javascript. To write it in old javascript it'd be:
var matchingStudents = array.filter(function(student){
return data.find(function(jsonData){ return student.id === jsonData.id});
}
To specifically answer your question Am I doing something incorrectly over here?
Your search code here assumes that array and data will contain the exact same ids in the exact same order:
for (let j =0; j < data.length; j++) {
if (array[j]["id"] === data[j].id) {
Based on the sample data you provided, this isn't the case; you can't always compare array[j] to data[j] to match ids because (for example) it's possible you need to match array[4] to data[6].
One solution to this problem is to use a nested loop:
for (let i = 0; i < array.length; i++) {
for (let j = 0; j < data.length; j++) {
if (array[i].id === data[j].id) {
This way you'll compare every entry in array to every entry in data when looking for matches. (This is similar to what the solutions suggesting array.map and data.find are doing, with some smart early-out behavior.)
Another approach would be to sort both lists and step forward through them together.
let array = [
{ "id": 134, "name": "student1" },
{ "id": 139, "name": "student2" },
{ "id": 136, "name": "student3" }
];
let data = [
{ "id": 134, "score": 45 },
{ "id": 138, "score": 67 },
{ "id": 139, "score": 34 }
];
array.sort((a, b) => a.id - b.id)
data.sort((a, b) => a.id - b.id)
let data_i = 0;
for (let array_i = 0; array_i < array.length; array_i++) {
while (data[data_i].id < array[array_i].id) {
data_i++;
}
if (data_i < data.length && data[data_i].id === array[array_i].id) {
console.log(`Matched ${array[array_i].name} to score ${data[data_i].score}`);
} else {
console.log(`No match found for ${array[array_i].name}`);
}
}

How does `lookupIndex[row[lookupKey]] = row;` work?

I am reading learnjsdata.com and came across this unfamiliar JavaScript syntax. The syntax is as follows:
lookupIndex[row[lookupKey]] = row;
Anyone know what's happening here? I haven't seen syntax like this. Used in context:
Data
var articles = [{
"id": 1,
"name": "vacuum cleaner",
"weight": 9.9,
"price": 89.9,
"brand_id": 2
}, {
"id": 2,
"name": "washing machine",
"weight": 540,
"price": 230,
"brand_id": 1
}, {
"id": 3,
"name": "hair dryer",
"weight": 1.2,
"price": 24.99,
"brand_id": 2
}, {
"id": 4,
"name": "super fast laptop",
"weight": 400,
"price": 899.9,
"brand_id": 3
}];
var brands = [{
"id": 1,
"name": "SuperKitchen"
}, {
"id": 2,
"name": "HomeSweetHome"
}];
Function & Invocation
function join(lookupTable, mainTable, lookupKey, mainKey, select) {
var l = lookupTable.length,
m = mainTable.length,
lookupIndex = [],
output = [];
for (var i = 0; i < l; i++) { // loop through l items
var row = lookupTable[i];
lookupIndex[row[lookupKey]] = row; // create an index for lookup table
}
for (var j = 0; j < m; j++) { // loop through m items
var y = mainTable[j];
var x = lookupIndex[y[mainKey]]; // get corresponding row from lookupTable
output.push(select(y, x)); // select only the columns you need
}
return output;
};
var result = join(brands, articles, "id", "brand_id", function(article, brand) {
return {
id: article.id,
name: article.name,
weight: article.weight,
price: article.price,
brand: (brand !== undefined) ? brand.name : null
};
});
console.log(result);
Appreciate any answers or pointers, thanks!
Think of it as two separate function calls:
var rowLookup = row[lookupKey];
lookupIndex[rowLookup] = row;
It's the same as doing it all in the same line:
lookupIndex[row[lookupKey]] = row;

Categories