Compare two arrays javascript - javascript

I'm working on puppeteer in nike website.
I'm getting the sizes and stock and showing it as an array,
{ sku: 72961, skuname: 'Talla: 6 - Color: Azul', quantity: 2 },
{ sku: 72962, skuname: 'Talla: 6.5 - Color: Azul', quantity: 4 },
{ sku: 72963, skuname: 'Talla: 7 - Color: Azul', quantity: 5 },
{ sku: 72964, skuname: 'Talla: 7.5 - Color: Azul', quantity: 7 },
{ sku: 72965, skuname: 'Talla: 8 - Color: Azul', quantity: 6 },
{ sku: 72966, skuname: 'Talla: 8.5 - Color: Azul', quantity: 5 },
{ sku: 72967, skuname: 'Talla: 9 - Color: Azul', quantity: 8 },
{ sku: 72968, skuname: 'Talla: 9.5 - Color: Azul', quantity: 8 },
{ sku: 72969, skuname: 'Talla: 10 - Color: Azul', quantity: 6 },
{ sku: 72970, skuname: 'Talla: 10.5 - Color: Azul', quantity: 4 },
{ sku: 72971, skuname: 'Talla: 11 - Color: Azul', quantity: 1 },
{ sku: 72972, skuname: 'Talla: 11.5 - Color: Azul', quantity: 2 }
]
That is refreshing each 10 seconds so I'd like to find a way that the last array is compared to the previous to know if a new Size or quantity is added
My code
const pagina = "https://nike.cl"
const producto = "/dm0121-400-nike-dunk-low-retro-qs/p"
const page = await browser.newPage();
await page.setViewport({ width: 1440, height: 900});
while (true) {
await page.goto(pagina + producto, { waitUntil: 'networkidle2' },);
var SKU = await page.evaluate("skuJson_0")
let filter = SKU.skus.filter( d => d.availablequantity > 0)
var SKUfiltered = filter.map(function(d){
return{
sku: d.sku,
skuname: d.skuname,
quantity: d.availablequantity
}})
console.log(SKUfiltered)
await page.waitForTimeout(10000)

I think the best solution is store the SKU data to check if exists previously and if the value are equals.
If the value pass the two checks you could store it in your "SKU register".
As next step, you could make another checks to filter the value. In your case only check if the quantity is zero.
As a complement, if you get many SKU and store a huge maybe you reach the memory limit. So you could remove it if the array is too big. To make that you could create an Array to store the values in order and remove if you reach some limit like 1000 elements.
In the next example, I simulate get the data in each getSKU execution. You must adapt the code to your solution:
// == FAKE DATA ==
let res_i = 0;
const res_data = [
[
{ sku: 1, skuname: "1", quantity: 0 }, // empty
{ sku: 2, skuname: "2", quantity: 1 },
],
[
{ sku: 1, skuname: "1", quantity: 5 },
{ sku: 2, skuname: "2", quantity: 1 }, // same quantity
{ sku: 3, skuname: "3", quantity: 0 }, // empty
],
[
{ sku: 1, skuname: "1", quantity: 0 }, // empty
{ sku: 3, skuname: "3", quantity: 3 },
{ sku: 4, skuname: "4", quantity: 3 },
],
];
// == END FAKE DATA ==
// An array to save the lastest SKU and a Map to store important values
const SKURegLog = [];
const SKURegdata = new Map();
// A funtion to simulate the data
function getSKU() {
const SKU = res_data[res_i++]; // Simulate the incoming data
return SKU.filter((v) => {
// Get the current SKU in the register
const curSKU = SKURegdata.get(v.sku);
// If exists and the quantity is the same, discard
if (curSKU !== undefined && curSKU.quantity === v.quantity) {
return false;
}
// If the SKU not exists in register add to the array
if (curSKU === undefined) {
SKURegLog.push(v.sku);
}
// Include the SKU in the register. If the array reach
// the limit (1000) delete the olders
SKURegdata.set(v.sku, {quantity: v.quantity});
if (SKURegLog.length > 1000) {
const oldSKU = SKURegLog.shift();
SKURegdata.delete(oldSKU);
}
// Check the current quantity
if (v.quantity === 0) {
return false;
}
// Include the SKU
return true;
});
}
console.log(getSKU());
console.log(getSKU());
console.log(getSKU());
console.log("= Register data:");
console.log(SKURegLog);
console.log(SKURegdata);
Output:
1: [ { sku: 2, skuname: '2', quantity: 1 } ]
2: [ { sku: 1, skuname: '1', quantity: 5 } ]
3: [ { sku: 3, skuname: '3', quantity: 3 }, { sku: 4, skuname: '4', quantity: 3 }]
== Register data:
[ 1, 2, 3, 4 ]
Map(4) {
1 => { quantity: 0 },
2 => { quantity: 1 },
3 => { quantity: 3 },
4 => { quantity: 3 }
}

Related

filter array of objects by methods of another array of objects [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I am making a food delivery app and I have two different array of objects. One of them is cartItems and the other is foodItems. The arrays can be of different sizes. So what do I want to loop over each array and check
if the ids of both the array match.
Note I want to check if the quantity exists then increment it by the new quantity else simply add a new quantity
check if itemDetails exists in foodItems array and if it exists, check if the price of cartItems matches of that foodItem, then update the cartItems object, else remove them.
if itemDetails does not exist then update the quantity of the item.
Update
If there are two items with similar id and price, the quantities should be added
Here is my cartItems:
let cartItems = [
{ id: 1, price: 120, quantity: 7 },
{ id: 2, price: 70, quantity: 4 },
{ id: 1, price: 70, quantity: 3 },
{ id: 3, price: 60, quantity: 1 },
{id: 1, price: 120, quantity: 2}
];
Here is my foodItems
let foodItems = [
{
id: 1,
name: "chicken",
itemDetails: [
{
price: 120,
details: "2 pcs of chicken biryani"
},
{
price: 70,
details: "1 pcs of chicken biryani"
}
],
},
{
id: 2,
name: "Mutton",
itemDetails: [
{
price: 120,
details: "Two pieces of mutton biryani",
},
{
price: 70,
details: "one pcs of mutton biryani"
},
],
},
{ id: 3, name: "Ice Cream", price: 60 },
];
This is my desired output
let filteredArrayOuput = [
{
id: 1,
name: "Chicken Biryani",
itemDetails: [
{
price: 120,
details: "Two pieces of chicken Biryani",
},
],
quantity: 7,
},
{
id: 2,
name: "Mutton Biryani",
itemDetails: [
{
price: 70,
details: "Two pieces of mutton biryani",
},
],
quantity: 4,
},
{
id: 1,
price: "Chicken Biryani",
quantity: 3,
itemDetails: [
{
price: 70,
details: "Two pieces of Chicken Biryani",
},
],
},
{ id: 3, price: 60, quantity: 1 },
];
This is what I have done till now
const filterFunc = (arr, price) => {
let filtered = arr.filter((item) => {
return item.price == price;
});
return filtered;
};
const filterArray = (arr1, arr2) => {
const filtered = arr2.filter((el) => {
let arr = arr1.find(({ id, quantity, price }) => {
if (el.id === id) {
if (el.itemDetails !== undefined && el.itemDetails.length !== 0) {
let itemDetails = el.itemDetails;
return (
(el.quantity = quantity),
(el.itemDetails = filterFunc(itemDetails, price))
);
} else {
return (el.quantity = quantity);
}
}
});
return arr;
});
return filtered;
};
console.log(filterArray(cartItems, foodItems))
You can check the below code.
Find existingFoodItem from FoodItems array
Find priceObj by comparing price
return new object with price details if itemDetails exists (checking with ?), else without price if no itemDetails exists.
let cartItems = [
{ id: 1, price: 120, quantity: 7 },
{ id: 1, price: 120, quantity: 1 },
{ id: 2, price: 70, quantity: 4 },
{ id: 1, price: 70, quantity: 3 },
{ id: 3, price: 60, quantity: 1 },
];
let foodItems = [
{
id: 1,
name: "chicken",
itemDetails: [
{
price: 120,
details: "2 pcs of chicken biryani"
},
{
price: 70,
details: "1 pcs of chicken biryani"
}
],
},
{
id: 2,
name: "Mutton",
itemDetails: [
{
price: 120,
details: "Two pieces of mutton biryani",
},
{
price: 70,
details: "one pcs of mutton biryani"
},
],
},
{ id: 3, name: "Ice Cream", price: 60 },
];
let result = [];
cartItems.forEach(cart => {
let esitingItem = result.find(r => r.id === cart.id && r.itemDetails.find(i => i.price === cart.price));
if(esitingItem){
esitingItem.quantity += cart.quantity;
return;
}
let existingFoodItem = foodItems.find(food => food.id === cart.id);
if(existingFoodItem){
let priceObj = existingFoodItem.itemDetails?.find(item => item.price === cart.price);
if(priceObj){
result.push({id:cart.id,name:existingFoodItem.name,itemDetails:[{...priceObj}],quantity:cart.quantity});
}
else{
return result.push({id:cart.id,name:existingFoodItem.name,quantity:cart.quantity});
}
}
});
console.log(result);

How to check for at least one object inside another object

I need to validate a form field.
this is the categories field inside my form.
categories = {
category1: [
{ id: 1, quantity: 0 },
{ id: 2, quantity: 0 }
],
category2: [
{ id: 3, quantity: 0 },
{ id: 4, quantity: 0 }
],
category3: [
{ id: 5, quantity: 0 },
{ id: 6, quantity: 0 }
]
}
this is how I check if AT LEAST ONE array element passes a test inside EACH category.
for (const category in categories) {
let theOne = categories[category].some(product => product.quantity !== 0);
}
this way the form will be valid if at least one quantity inside EACH category will hold a value of 1.
// I DONT WANT THIS
categories = {
category1: [
{ id: 1, quantity: 1 }, // at least one quantity value is 1
{ id: 2, quantity: 0 }
],
category2: [
{ id: 3, quantity: 1 }, // at least one quantity value is 1
{ id: 4, quantity: 0 }
],
category3: [
{ id: 5, quantity: 1 }, // at least one quantity value is 1
{ id: 6, quantity: 0 }
]
}
// I NEED THIS
categories = {
category1: [
{ id: 1, quantity: 1 }, // at least one quantity value is 1
{ id: 2, quantity: 0 }
],
category2: [
{ id: 3, quantity: 0 }, // not needed
{ id: 4, quantity: 0 }
],
category3: [
{ id: 5, quantity: 0 }, // not needed
{ id: 6, quantity: 0 }
]
}
how is it possible to make it work for at least one category ?
That is to check them all:
const categories = {
category1: [{ id: 1, quantity: 0 }],
category2: [{ id: 2, quantity: 1 }],
category3: [{ id: 3, quantity: 0 }]
};
const didIPass = Object.values(categories).some((category) => {
return category.some((subCategory) => subCategory.quantity !== 0);
});
console.log('Did I pass?', didIPass);
That is to check inside each specifically:
Object.entries(categories).forEach((entry) => {
const key = entry[0];
const value = entry[1];
const didIPass = value.some((subCategory) => subCategory.quantity !== 0);
console.log(`Did ${key} pass? ${didIPass}`);
});
Will produce the output:
Did I pass? true
Did category1 pass? false
Did category2 pass? true
Did category3 pass? false

Cant implement correct sorting in javaScript using Array.sort

I have an array of profiles and each array contain profile object that contain "rating" object that contains 2 values:
Field named "totalRates" - that hold the value of total sum of rates per profile
Array named "rates" - array of objects that contains users id and the value each user rated for this spesific profile.
I want to get the top 3 rated user.
For that i have to map over all profiles and for each profile take the total rate of profile divide by rates.length to get the average and sort.
So what i did is:
router.get('/rating/top',async (req,res)=>{
try{
const profiles=await Profile.find().populate('user',['name','avatar'])
const ratedProfiles = profiles.map(( profile) =>{
if(profile.rating.rates.length>0)
return profile
})
//'BEFORE SORT'
const topRated = ratedProfiles.sort((a, b) => (a.rating.totalRates/a.rating.rates.length) - (b.rating.totalRates/b.rating.rates.length));
//AFTER SORT'
}
catch(err){
console.error(err.message);
res.status(500).send('Server error');
}
})
the first cell from my output in ratedProfiles:
{
[0] rating: { totalRates: 5, rates: [Array] },
[0] skills: [ 'css' ],
[0] _id: 5f3c3be9ebadb42a189640d5,
[0] user: {
[0] _id: 5f3c3bd1ebadb42a189640d4,
[0] name: 'Yosef Zaltsman',
[0] avatar: 'http://localhost:5000/public/5f3c3bd1ebadb42a189640d4.jpeg'
[0] },
[0] gender: '0',
[0] status: 'Junior Developer',
[0] experience: [],
[0] education: [],
[0] __v: 1
[0] },
I got same results before and after sorting.
What did i do wrong?
You need to sum up all the values of each rating and then divide this sum by the total number of ratings (i.e. calculating the average rating). Then you can sort by this average and take the first three values of the resulting array.
Here's a very "verbose" way to do this in order to to show you what's going on:
const ratedProfiles = [
{ rating: { totalRates: 5, rates: [{ value: 10 }, { value: 30 }, { value: 10 }, { value: 10 }, { value: 20 }] } },
{ rating: { totalRates: 1, rates: [{ value: 20 }] } },
{ rating: { totalRates: 2, rates: [{ value: 20 }, { value: 40 }] } },
{ rating: { totalRates: 3, rates: [{ value: 5 }, { value: 3 }, { value: 2 }] } },
{ rating: { totalRates: 4, rates: [{ value: 1 }, { value: 3 }, { value: 2 }, { value: 8 }] } },
];
const mappedSumRatedProfiles = ratedProfiles.map(profile => {
const sum = profile.rating.rates.reduce((prev, rate) => rate.value + prev, 0);
return { rating: { ...profile.rating }, avg: sum / profile.rating.totalRates };
});
mappedSumRatedProfiles.sort((a, b) => {
return b.avg - a.avg;
});
console.log(mappedSumRatedProfiles.slice(0,3));

Comparing Two Arrays and Grouping into Inserts and Updates

I am comparing two arrays and then grouping them into inserts and updates. The updates array should end up including elements that match on id == Id, but where open_balance !- DocumentAmount. The inserts array should include only elements where the id != Id. Notice I am running both through the toString() method because in my scenario one is of type String whereas the other is of type Integer from two different SQL Databases.
Now, with the code I have now, the first grouping works - via the findRecordsToUpdate() function, I get all of the elements matched correctly for the updates - which should be two elements, because these two match on id, but not on the amount:
recordsToUpdate: [
{ Id: '333', DocumentAmount: 20 },
{ Id: '444', DocumentAmount: 10 }
]
But the inserts, which is produced by the findRecordsToInsert() function, are not correct. According to my data I should end up with one element, with an Id of '555' in my recordsToUpdate array, because it's the only element with an Id not found in the other array -- i.e. it's a new record to insert. But instead I end up with 13 elements with my current code?
What am I missing here and what do I need to change to get the correct inserts populated to my recordsToInsert array?:
const sourceArr = [
{ id: 111, open_balance: 10 },
{ id: 222, open_balance: 20 },
{ id: 333, open_balance: 10 },
{ id: 444, open_balance: 20 },
]
const targetArr = [
{ Id: '111', DocumentAmount: 10 },
{ Id: '222', DocumentAmount: 20 },
{ Id: '333', DocumentAmount: 20 },
{ Id: '444', DocumentAmount: 10 },
{ Id: '555', DocumentAmount: 10 },
]
function findRecordsToUpdate () {
if (sourceArr.length && targetArr.length) {
let recordsToUpdate = [];
for (let t of targetArr) {
for (let s of sourceArr) {
if ((t.Id.toString() == s.id.toString()) && (t.DocumentAmount != s.open_balance)) {
recordsToUpdate.push(t);
}
}
}
console.log('recordsToUpdate: ', recordsToUpdate);
return recordsToUpdate;
}
};
function findRecordsToInsert () {
if (sourceArr.length && targetArr.length) {
let recordsToInsert = [];
for (let t of targetArr) {
for (let s of sourceArr) {
if (t.Id.toString() != s.id.toString()) {
recordsToInsert.push(t);
}
}
}
console.log('recordsToInsert: ', recordsToInsert);
return recordsToInsert;
}
};
findRecordsToUpdate();
findRecordsToInsert();
By the way, to clarify, my findRecordsToInsert() function should return a recordsToInsert array like this when done, as the record with an Id of 555 is the only record from the second array that doesn't exist in the first array:
recordsToInsert: [{ Id: '555', DocumentAmount: 10 }]
So, to be clear, it's just the findRecordsToInsert() function that is not working correctly at present.
Use a combination of Array#filter and Array#find to get your insert and update arrays out of targetArr.
'use strict';
const sourceArr = [
{ id: 111, open_balance: 10 },
{ id: 222, open_balance: 20 },
{ id: 333, open_balance: 10 },
{ id: 444, open_balance: 20 },
];
const targetArr = [
{ Id: '111', DocumentAmount: 10 },
{ Id: '222', DocumentAmount: 20 },
{ Id: '333', DocumentAmount: 20 },
{ Id: '444', DocumentAmount: 10 },
{ Id: '555', DocumentAmount: 10 },
];
// Target records with a matching source (on ID) where the amount has changed.
// Update these.
const recordsToUpdate = targetArr
.filter(tar => sourceArr
.find(source => source.id === Number(tar.Id) && source.open_balance !== tar.DocumentAmount));
console.log(recordsToUpdate);
// Target records that have no matching source record (i.e. new records).
// Insert these.
const recordsToInsert = targetArr
.filter(tar => !sourceArr
.find(source => source.id === Number(tar.Id)));
console.log(recordsToInsert);
Edit
Just for the record, in your original code the search in findRecordsToInsert is incorrect. To fix the issue, try to find each target in source and, if not found, add target to the insert array. But it's just a long-winded version of filter-find.
const sourceArr = [
{ id: 111, open_balance: 10 },
{ id: 222, open_balance: 20 },
{ id: 333, open_balance: 10 },
{ id: 444, open_balance: 20 },
]
const targetArr = [
{ Id: '111', DocumentAmount: 10 },
{ Id: '222', DocumentAmount: 20 },
{ Id: '333', DocumentAmount: 20 },
{ Id: '444', DocumentAmount: 10 },
{ Id: '555', DocumentAmount: 10 },
]
function findRecordsToInsert () {
if (sourceArr.length && targetArr.length) {
const recordsToInsert = [];
for (const t of targetArr) {
let found = false;
for (let i = 0; i < sourceArr.length && !found; ++i) {
if (t.Id.toString() === sourceArr[i].id.toString())
found = true;
}
if (!found)
recordsToInsert.push(t);
}
console.log('recordsToInsert: ', recordsToInsert);
return recordsToInsert;
}
};
findRecordsToInsert();
You could take a hash table and just filter the target array.
const
sourceArr = [{ id: 111, open_balance: 10 }, { id: 222, open_balance: 20 }, { id: 333, open_balance: 10 }, { id: 444, open_balance: 20 }],
targetArr = [{ Id: '111', DocumentAmount: 10 }, { Id: '222', DocumentAmount: 20 }, { Id: '333', DocumentAmount: 20 }, { Id: '444', DocumentAmount: 10 }, { Id: '555', DocumentAmount: 10 }],
source = sourceArr.reduce((r, { id, open_balance }) => (r[id] = open_balance, r), {}),
recordsToUpdate = targetArr.filter(({ Id, DocumentAmount }) =>
Id in source && source[Id] !== DocumentAmount),
recordsToInsert = targetArr.filter(({ Id }) => !(Id in source));
console.log(recordsToUpdate);
console.log(recordsToInsert);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Array Merge based on two value

I have an array like:
Name Qty Price
happ 1 50
happ 1 50
happ 1 50
happ 2 10
app 1 50
app 1 50
app 1 50
app 2 10
and I have to convert and merge like that using JavaScript /jquery:
Name Qty Price
happ 3 50
happ 2 10
app 3 50
app 2 10
based on equal name and price
Any help should be appreciated.
I love such a tasks. They are not a difficult one and help to switch myself into working condition.
// Sample data
arr = [{ name: 'happ', qty: 1, price: 50 },
{ name: 'happ', qty: 1, price: 50 },
{ name: 'happ', qty: 1, price: 50 },
{ name: 'harr', qty: 1, price: 50 }];
result = {};
// Summarize array by one walk
arr.forEach(function(k) {
if (!result[k.name + k.price]) {
result[k.name + k.price] = k;
} else {
result[k.name + k.price].qty += k.qty;
}
});
// convert object to array by one walk
var finalResult = [];
for (var key in result) { finalResult.push(result[key]) }
This problem is equivalent to the SQL query:
SELECT name, sum(qty), price
FROM dataObject
GROUP BY name, price
ORDER BY sum(qty) DESC
You can use the native functions .reduce() to aggregrate the data, and then .sort() to sort by qty:
HTML:
<div id="results"></div>
Javascript:
// Sample data
arr = [{ name: 'happ', qty: 1, price: 50 },
{ name: 'happ', qty: 1, price: 50 },
{ name: 'happ', qty: 1, price: 50 },
{ name: 'happ', qty: 2, price: 10 },
{ name: 'app', qty: 1, price: 50 },
{ name: 'app', qty: 1, price: 50 },
{ name: 'app', qty: 1, price: 50 },
{ name: 'app', qty: 2, price: 10 }];
var groupedObjects = arr.reduce(function(res, obj) {
if (!((obj.name + obj.price) in res))
res.__array.push(res[obj.name + obj.price] = obj);
else {
res[obj.name + obj.price].qty += obj.qty;
}
return res;
}, {__array:[]}).__array
.sort(function(a,b) { return b.qty - a.qty; });
// print results for testing
_.each(groupedObjects,function(obj){
var output = '';
_.each(obj,function(val,key){
output += key+': '+val+'<br>';
});
output += '<br>';
$('#results').append(output);
});
Output:
name: happ
qty: 3
price: 50
name: app
qty: 3
price: 50
name: happ
qty: 2
price: 10
name: app
qty: 2
price: 1
Working Demo

Categories

Resources