Javascript array equality control and changing value - javascript

Hi I have two changeable length arrays and I tried If there is no value I want, delete it from that array and change the sum value if it has changed array 2 same serials code
array1 = [
{
"serial": "3",
"sum": "1"
},
{
"serial": "700",
"sum": "2"
},
{
"serial": "300",
"sum": "1"
},
]
array2 = [{
"someting": 10,
"sum": "3",
"serialList": ["700","711"],
},
{
"someting": 10,
"sum": "1",
"serialList": ["300"],
},
{
"someting": 10,
"sum": "2",
"serialList": [],
}
]
his my two array as I said arrays length is changeable sometimes array1 length big, sometimes array2 and I want If serial number in array1 does not exist in array2 delete from array1 element and change the sum value if it has changed array2 same serials code, according to above array1[0] serial codes does not exist and array1[1] sum value different array2[0] sum value change to sum value array1[1] to array2[0], serial number 300 to same sum number to array don't do anything I want to output array1 is:
array1 = [
{
"serial": "700",
"sum": "3"
},
{
"serial": "300",
"sum": "1"
},
]

Using a flatMap
array1.flatMap(el => {
// find array2 element with array1 element's serial
const array2el = array2.find(({ serialList }) =>
serialList.includes(el.serial)
);
if (array2el) {
if (array2el.sum !== el.sum) {
el.sum = array2el.sum; // sum different, update
}
} else {
return []; // return [] to delete
}
return [el]; // return [el] to keep
});
const array1 = [
{
serial: "3",
sum: "1"
},
{
serial: "700",
sum: "2"
},
{
serial: "300",
sum: "1"
}
];
const array2 = [
{
someting: 10,
sum: "3",
serialList: ["700", "711"]
},
{
someting: 10,
sum: "1",
serialList: ["300"]
},
{
someting: 10,
sum: "2",
serialList: []
}
];
const processedArray1 = array1.flatMap(el => {
const array2el = array2.find(({ serialList }) =>
serialList.includes(el.serial)
);
if (array2el) {
if (array2el.sum !== el.sum) {
el.sum = array2el.sum;
}
} else {
return []; // delete
}
return [el]; // return el
});
console.log(processedArray1);
Using a reduce
const processedArray1 = array1.reduce((acc, el) => {
// find array2 element with array1 element's serial
const array2el = array2.find(({ serialList }) =>
serialList.includes(el.serial)
);
if (array2el) {
if (array2el.sum !== el.sum) {
el.sum = array2el.sum; // sum different, update
}
acc.push(el); // push into filtered array if found in array2
}
return acc;
}, []);
const array1 = [
{
serial: "3",
sum: "1"
},
{
serial: "700",
sum: "2"
},
{
serial: "300",
sum: "1"
}
];
const array2 = [
{
someting: 10,
sum: "3",
serialList: ["700", "711"]
},
{
someting: 10,
sum: "1",
serialList: ["300"]
},
{
someting: 10,
sum: "2",
serialList: []
}
];
const processedArray1 = array1.reduce((acc, el) => {
const array2el = array2.find(({ serialList }) =>
serialList.includes(el.serial)
);
if (array2el) {
if (array2el.sum !== el.sum) {
el.sum = array2el.sum;
}
acc.push(el)
}
return acc;
}, []);
console.log(processedArray1);

Related

Move objects in array where duplicates occur

I have an array of objects, each array has a key of name and then another array of objects:
const myArray = [ { name: "1", item: [{}] }, { name: "2", item: [{}] }, { name: "1", item: [{}] } ]
Now for example sometimes that name key will be the same, i want to be able to check if that name exists and if it does exist push the item into that array object and not into a new object.
The behaviour im getting is above but i would like:
const myArray = [ { name: "1", item: [{ item1, item2 etc }] }, { name: "2", item: [{}] }, { name: "3", item: [{}] } ]
Thanks so much in advance!
You can get the desired result using Array.reduce(), grouping by name.
If two objects in myArray share the same name, the item values are combined.
const myArray = [ { name: "1", item: [{ id: 1 }] }, { name: "2", item: [{ id: 2}] }, { name: "1", item: [{ id: 3}] } ]
const result = Object.values(myArray.reduce((acc, { name, item }) => {
acc[name] = acc[name] || { name, item: [] };
acc[name].item.push(...item);
return acc;
}, {}))
console.log('Result:', result)
.as-console-wrapper { max-height: 100% !important; }
Here's a solution using Array.prototype.reduce function.
const myArray = [ { name: "1", item: [{}] }, { name: "2", item: [{}] }, { name: "1", item: [{}] } ];
const output = myArray.reduce((acc, curr) => {
const index = acc.findIndex(pre => pre.name === curr.name);
if(index !== -1) {
acc[index].item = acc[index].item.concat(curr.item);
} else {
acc.push(curr);
}
return acc;
}, []);
console.log(output);

Comparing two arrays of objects for matching properties then creating two new arrays

I have the following two arrays:
var oldOrder = [{"Id": "10","Qty": 1}, {"Id": "3","Qty": 2}, {"Id": "9","Qty": 2}];
var newOrder = [{"Id": "5","Qty": 2},{"Id": "10","Qty": 3}, {"Id": "9","Qty": 1}];
I need to end up with a newArray containing only one object per Id, but if the ids in an object in the oldOrder array and newOrder array then I need to get the difference in the Qty positive or negative. So for example the above would create this new array:
var newArray = [{"Id": "5","Qty": 2},{"Id": "10","Qty": 2}, {"Id": "9","Qty": -1}];
I would also like to get the dropped orders that are present in the oldOrder Array but not in the newOrder array:
var droppedOrders = [{"Id": "3","Qty": 2}];
I have already got this logic for getting the dropped orders but I am struggling with creating the newArray and tying the logic into the same function if possible?
function comparer(otherArray){
return function(current){
var onlyInOld = otherArray.filter(function(other){
return other.Id == current.Id;
}).length == 0;
return onlyInOld;
}
}
var droppedOrders= oldOrder.filter(comparer(newOrder));
console.log(droppedOrders);
Edited to add that I cannot use ESC6 features like spread or fat arrow etc.
You can easily achieve the result using Map
1) Using ES6
var oldOrder = [
{ Id: "10", Qty: 1 },
{ Id: "3", Qty: 2 },
{ Id: "9", Qty: 2 },
];
var newOrder = [
{ Id: "5", Qty: 2 },
{ Id: "10", Qty: 3 },
{ Id: "9", Qty: 1 },
];
const oldMap = new Map(oldOrder.map((o) => [o.Id, o]));
const newMap = new Map(newOrder.map((o) => [o.Id, o]));
const result = newOrder.map((o) =>
oldMap.has(o.Id) ? { ...o, Qty: o.Qty - oldMap.get(o.Id).Qty } : o
);
const droppedOrders = oldOrder.filter(({ Id }) => !newMap.has(Id));
console.log(result);
console.log(droppedOrders);
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
.as-console-wrapper {
max-height: 100% !important;
top: 0;
}
2) Using ES5
var oldOrder = [
{ Id: "10", Qty: 1 },
{ Id: "3", Qty: 2 },
{ Id: "9", Qty: 2 },
];
var newOrder = [
{ Id: "5", Qty: 2 },
{ Id: "10", Qty: 3 },
{ Id: "9", Qty: 1 },
];
const oldMap = {};
const newMap = {};
oldOrder.forEach(function (o) {
oldMap[o.Id] = o;
});
newOrder.forEach(function (o) {
newMap[o.Id] = o;
});
const result = newOrder.map(function (o) {
return oldMap[o.Id]
? Object.assign({}, o, { Qty: o.Qty - oldMap[o.Id].Qty })
: o;
});
const droppedOrders = oldOrder.filter(function (o) {
return !newMap[o.Id];
});
console.log(result);
console.log(droppedOrders);
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }
Try using Array.map and Array.filter
var oldOrder = [{ "Id": "10", "Qty": 1 }, { "Id": "3", "Qty": 2 }, { "Id": "9", "Qty": 2 }];
var newOrder = [{ "Id": "5", "Qty": 2 }, { "Id": "10", "Qty": 3 }, { "Id": "9", "Qty": 1 }];
const newArray = newOrder.map((node) => {
const nodeFromOldArray = oldOrder.find((item) => item.Id === node.Id);
if (nodeFromOldArray) {
return {
Id: node.Id,
Qty: nodeFromOldArray.Qty - node.Qty
}
} else {
return node;
}
});
const droppedOrders = oldOrder.filter((item) => !newArray.find(node => node.Id === item.Id))
console.log(newArray);
console.log(droppedOrders);
One way to achieve that is by keying the old and new order arrays by Id. After keying everything else should be a simple as using filter and map:
var oldOrder = [{"Id": "10","Qty": 1}, {"Id": "3","Qty": 2}, {"Id": "9","Qty": 2}];
var newOrder = [{"Id": "5","Qty": 2},{"Id": "10","Qty": 3}, {"Id": "9","Qty": 1}];
var keyedOldOrder = keyBy(oldOrder, 'Id');
var keyedNewOrder = keyBy(newOrder, 'Id');
var newArray = newOrder.map(function (entity) {
var subtract = keyedOldOrder.hasOwnProperty(entity.Id)
? keyedOldOrder[entity.Id].Qty
: 0;
return Object.assign({}, entity, {
Qty: entity.Qty - subtract
});
});
var droppedOrders = oldOrder.filter(function (entity) {
return !keyedNewOrder.hasOwnProperty(entity.Id);
});
console.log(newArray);
console.log(droppedOrders);
function keyBy(array, field)
{
return array.reduce(function (carry, entity) {
carry[entity[field]] = entity;
return carry;
}, {});
}
You could take a Map and perform a single loop for every array and redere the result to the wanted target arrays.
const
addToMap = (map, target) => ({ Id, Qty }) => map.set(Id, { target, Qty: Qty - (map.get(Id)?.Qty || 0) }),
oldOrder = [{ Id: "10", Qty: 1 }, { Id: "3", Qty: 2 }, { Id: "9", Qty: 2 }],
newOrder = [{ Id: "5", Qty: 2 }, { Id: "10", Qty: 3 }, { Id: "9", Qty: 1 }],
map = new Map,
orders = [],
dropped = [];
oldOrder.forEach(addToMap(map, dropped));
newOrder.forEach(addToMap(map, orders));
map.forEach(({ target, Qty }, Id) => target.push({ Id, Qty }));
console.log(orders);
console.log(dropped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
An approach with older Javascript by taking an object instead of Map.
The algorithm is the same as above.
const
addToMap = function(map, target) {
return function (o) {
map[o.Id] = { target: target, Qty: o.Qty - (map[o.Id] && map[o.Id].Qty || 0) };
};
},
oldOrder = [{ Id: "10", Qty: 1 }, { Id: "3", Qty: 2 }, { Id: "9", Qty: 2 }],
newOrder = [{ Id: "5", Qty: 2 }, { Id: "10", Qty: 3 }, { Id: "9", Qty: 1 }],
map = {},
orders = [],
dropped = [];
oldOrder.forEach(addToMap(map, dropped));
newOrder.forEach(addToMap(map, orders));
Object
.keys(map)
.forEach(function(Id) {
map[Id].target.push({ Id: Id, Qty: map[Id].Qty });
});
console.log(orders);
console.log(dropped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

String-path to Tree (JavaScript)

I have an array of paths in string format like that:
[
{ _id: 'women/clothes/tops', count: 10 },
{ _id: 'women/clothes/suits', count: 5 },
{ _id: 'women/accessories', count: 2 },
{ _id: 'men/clothes', count: 1 },
]
I would like to group them into a tree structure like that:
[
{
_id: 'women',
count: 17,
children: [
{
_id: 'clothes',
count: 15,
children: [
{ _id: 'tops', count: 10 },
{ _id: 'suits', count: 5 }
]
},
{
_id: 'accessories',
count: 2
}
]
},
{
_id: 'men',
count: 1,
children: [
{
_id: 'clothes',
count: 1
}
]
}
]
I would imagine a sort of recursive function calling a reduce method. But I can't figure how exactly.
EDIT :
I managed to get close with this solution. But I still get an empty object key, and i cannot manage to not have the children key when there are no children:
const getTree = (array) => {
return array.reduce((a, b) => {
const items = b._id.replace('\/', '').split('/')
return construct(a, b.count, items)
}, {})
}
const construct = (a, count, items) => {
const key = items.shift()
if(!a[key]) {
a[key] = {
_id: key,
count: count,
children: []
}
a[key].children = items.length > 0 ? construct(a[key].children, count, items) : null
}
else {
a[key].count += count
a[key].children = items.length > 0 ? construct(a[key].children, count, items) : null
}
return a
}
I created an object tree first and then converted that to your array of objects with children structure.
Note: I used a _count property on each object in the intermediate structure so that when looping over the keys later (when creating the final structure), I could ignore both _id and _count easily, and loop over only the "real children" keys, which don't start with _.
I did not look at your current attempt/solution before writing this, so mine looks quite different.
const origData = [
{ _id: 'women/clothes/tops', count: 10 },
{ _id: 'women/clothes/suits', count: 5 },
{ _id: 'women/accessories', count: 2 },
{ _id: 'men/clothes', count: 1 },
];
const newObj = {};
for (let obj of origData) {
//console.log(obj)
const tempArr = obj._id.split('/');
let tempHead = newObj; // pointer
for (let idx in tempArr) {
let head = tempArr[idx];
if (!tempHead.hasOwnProperty(head)) {
tempHead[head] = {};
}
tempHead = tempHead[head];
tempHead._id = head;
const currCount = tempHead._count || 0;
tempHead._count = currCount + obj.count;
}
tempHead._count = obj.count;
}
console.log(newObj);
const finalArr = [];
let tempArrHead = finalArr; // pointer
let tempObjHead = newObj; // pointer
function recursiveStuff(currObj, currArr, copyObj) {
let hasChildren = false;
const keys = Object.keys(currObj).filter(a => !a.startsWith("_"));
for (let key of keys) {
hasChildren = true;
const obj = {
_id: currObj[key]._id,
count: currObj[key]._count || 0,
children: [],
};
currArr.push(obj);
recursiveStuff(currObj[key], obj.children, obj)
}
if (hasChildren == false) {
// console.log(copyObj);
// there might be a more elegant way, but this works:
delete copyObj.children;
}
}
recursiveStuff(tempObjHead, tempArrHead)
console.log(finalArr);
.as-console-wrapper{
max-height: 100% !important;
}
Intermediate Structure:
{
"women": {
"_id": "women",
"_count": 17,
"clothes": {
"_id": "clothes",
"_count": 15,
"tops": {
"_id": "tops",
"_count": 10
},
"suits": {
"_id": "suits",
"_count": 5
}
},
"accessories": {
"_id": "accessories",
"_count": 2
}
},
"men": {
"_id": "men",
"_count": 1,
"clothes": {
"_id": "clothes",
"_count": 1
}
}
}
Final Structure:
[
{
"_id": "women",
"count": 17,
"children": [
{
"_id": "clothes",
"count": 15,
"children": [
{"_id": "tops", "count": 10},
{"_id": "suits", "count": 5}
]
},
{"_id": "accessories", "count": 2}
]
},
{
"_id": "men",
"count": 1,
"children": [
{"_id": "clothes", "count": 1}
]
}
]

Count and update duplicate entries from array

I have an array with duplicated entries.
I'm looking for:
removing all duplicate occurrences
And increment the val propertie off an element if we find an occurrence
here is an exemple of what I have:
const arr = [
{"id":"46","name":"Productivity","val":1},
{"id":"1","name":"test","val":1},
{"id":"43","name":"Health and Fitness","val":1},
{"id":"46","name":"Productivity","val":1},
{"id":"1","name":"test","val":1},
{"id":"46","name":"Productivity","val":1}
]
// Wanted result
const result = [
{"id":"46","name":"Productivity","val":3},
{"id":"43","name":"Health and Fitness","val":1},
{"id":"1","name":"test","val":2}
]
Here is a JsFiddle
You can easily achieve this using reduce and object destructuring.
const arr = [
{ id: "46", name: "Productivity", val: 1 },
{ id: "1", name: "test", val: 1 },
{ id: "43", name: "Health and Fitness", val: 1 },
{ id: "46", name: "Productivity", val: 1 },
{ id: "1", name: "test", val: 1 },
{ id: "46", name: "Productivity", val: 1 },
];
const result = arr.reduce((acc, curr) => {
const { id, name, val } = curr;
const isPresent = acc.find((el) => el.id === id);
if (!isPresent) acc = [...acc, { id, name, val }];
else isPresent.val = isPresent.val + val;
return acc;
}, []);
console.log(result);

Combining same objects in json array javascript

I have this array:
[{ "id": 1, "myId": "100", "name": "amey" }, { "id": 2, "myId": "100", "name": "anuj" }, { "id": 3, "myId": "101", "name": "suraj" }, { "id": 4, "myId": "101", "name": "suraj h" }]
I want output like this:
[{ "id": 1, "myId": "100", "name": ["amey", "anuj"] }, { "id": 3, "myId": "101", "name": ["suraj", "suraj h] }]
How can I do this using javascript
for (var i = 0; i < myarray.length; i++) {
//And loop again for duplicate data
for (var j = i + 1; j < myarray.length; j++) {
if (
myarray[i].VENDOR_ID == myarray[j].VENDOR_ID &&
myarray[i].ORDER_ID === myarray[j].ORDER_ID
) {
var tmp = myarray[j].NAME;
console.log(tmp);
myarray[j].NAME = [];
myarray[j].NAME.push(tmp);
myarray[j].NAME.push(myarray[i].NAME);
myarray[i] = {};
}
}
}
You can use an array reduce into an object and return the array of values. Reduce into an object using the myId property as the key to group by. Shallow copy any existing state and and name array, appending the new name value from the current element.
Object.values(
input.reduce(
(acc, { id, myId, name }) => ({
...acc,
[myId]: {
...(acc[myId] || { id, myId }),
name: [...(acc[myId]?.name || []), name]
}
}),
{}
)
const input = [
{ id: 1, myId: "100", name: "amey" },
{ id: 2, myId: "100", name: "anuj" },
{ id: 3, myId: "101", name: "suraj" },
{ id: 4, myId: "101", name: "suraj h" }
];
const res = Object.values(
input.reduce(
(acc, { id, myId, name }) => ({
...acc,
[myId]: {
...(acc[myId] || { id, myId }),
name: [...(acc[myId]?.name || []), name]
}
}),
{}
)
);
console.log(JSON.stringify(res));
You can use Array.prototype.reduce():
const arr1 = [{
"id": 1,
"myId": "100",
"name": "amey"
}, {
"id": 2,
"myId": "100",
"name": "anuj"
}, {
"id": 3,
"myId": "101",
"name": "suraj"
}, {
"id": 4,
"myId": "101",
"name": "suraj h"
}]
const reduced = arr1.reduce((acc, item) => {
// 1. check if the 'acc' array already contains an item with the same 'myId' attribute
const itemIndex = acc.findIndex(it => it.myId === item.myId);
// 2. if there isn't any, push into the 'acc' array a copy of the item,
// with the 'name' property converted into an array of strings
// otherwise simply push the 'name' into the already existing item
if (itemIndex === -1) {
acc.push({
...item,
name: [item.name]
});
} else {
acc[itemIndex].name.push(item.name)
}
return acc;
}, []);
// test
console.log(reduced);

Categories

Resources