Values from three arrays - Add or subtract - javascript

I have three arrays:
Each array has a "key" and a "value" for every element, for example
array:
0: {key: "000001", value: 10}
1: {key: "000002", value: 20}
// other values
array1:
0: {key: "000001", value: 5}
1: {key: "000003", value: 15}
// other values
array3:
0: {key: "000001", value: 10}
1: {key: "000003", value: 3}
// other values
And this structure is the same for the three different arrays.
Now I need to check if in these three array there are keys equal and sum or subtract the field "value"
For example:
array, array1 and array2 have the key= "000001" in all the three
arrays so I sum the three value = 25.
In this way I will write only the "key" field and the sum of the "value"
I hope I was clear
I have tried in this way, but it doesn't work as I would like:
let outputTot = [];
output.filter((newDataOutput) => {
return output1.filter((newDataOutput1) => {
return output2.filter((newDataOutput2) => {
if(newDataOutput.key == newDataOutput1.key && newDataOutput.key == newDataOutput2.key){
outputTot.push({
'key': newDataOutput.key,
'value': newDataOutput.value + newDataOutput1.value + newDataOutput2.value
})
}
else if(newDataOutput.key == newDataOutput1.key){
outputTot.push({
'key': newDataOutput.key,
'value': newDataOutput.value + newDataOutput1.value
})
}
else if(newDataOutput.key == newDataOutput2.key){
outputTot.push({
'key': newDataOutput.key,
'value': newDataOutput.value + newDataOutput2.value
})
}
else if(newDataOutput1.key == newDataOutput2.key){
outputTot.push({
'key': newDataOutput1.key,
'value': newDataOutput1.value + newDataOutput2.value
})
}
})
})
})
I had thought of calculating all 4 cases but obviously it doesn't work like that.
How could I do?
EDIT:
What I expect:
my outputTot like:
> [0] key: "000001", value: 25
> [1] key: "000002", value: 20
> [2] kye: "000003", value: 18

I assume, you need reduce function to achieve the expected output. You can first group by the data using key and then take Object.values to get array out of it.
const arr = [{key: "000001", value: 10},{key: "000002", value: 20}];
const arr1 = [{key: "000001", value: 5},{key: "000002", value: 20}];
const arr2 = [{key: "000001", value: 10},{key: "000003", value: 3}];
const result = Object.values([...arr,...arr1,...arr2].reduce((a,{key, value}, i)=>{
a[key] ??= {key, value:0};
i==2 ? a[key].value-=value : a[key].value+=value;
return a;
},{}));
console.log(result);

Related

filtering nested objects in javascript

I have the following nested objects in javascript and I would like to filter based on a specific condition (value < 7). How can I do this in JS?
Input:
const data = [
{key: 'a', value: [{key: 'aa', value: 6}, {key: 'ab', value: 10}]},
{key: 'b', value: [{key: 'ba', value: 3}, {key: 'bb', value: 11}]}
]
Expected output:
const data = [
{key: 'a', value: [{key: 'aa', value: 6}]},
{key: 'b', value: [{key: 'ba', value: 3}]}
]
I have tried already some and filter but it is not working as expected.
Thanks!
Assuming you can use arrow functions:
const filteredData = data.map(item => {
item.value = item.value.filter(subItem => subItem.value < 7);
return item;
});
And if you're working in an environment where you can use the spread operator:
const filteredData = data.map(item => ({
...item,
value: item.value.filter(subItem => subItem.value < 7),
}));
Recursive function, without touching the original object
const data = [
{key: 'a', value: [{key: 'aa', value: 6}, {key: 'ab', value: 10}]},
{key: 'b', value: [{key: 'ba', value: 3}, {key: 'bb', value: 11}]}
];
const filterData = (dataOriginal, minValue) => {
//INFO: create copy of the object
const d = JSON.parse(JSON.stringify(dataOriginal));
//-----
return d.filter((item,i) => {
if(typeof item.value === 'number'){
return item.value < minValue;
} else if(Array.isArray(item.value)) {
const f = filterData(item.value, minValue);
d[i].value = f;
return !!f.length;
}
});
};
const filtered = filterData(data, 7);
console.log(filtered);
There are many ways, but how about e.g. this:
for (const o of data) o.value = o.value.filter(e => e.value < 7);

How can i subtract object values having similar keys in an array of object? (not to be confused with removing duplicates) [duplicate]

This question already has answers here:
How to remove all duplicates from an array of objects?
(77 answers)
Closed 1 year ago.
Let's say I have an object
const testArray = [{key: 'a', value: 5}, {key: 'b', value: 1}, {key: 'a', value: 2}]
what I want is
newArray = [{key: 'a', value: 3}, {key: 'b', value: 1}]
What I tried is
testArray.reduce((acc, cur, index) => {
const exists = !!acc && acc.find(item => item.key === cur.key)
if (!exists){
acc.push(cur)
} else {
// can't figure out what i should do here
}
return acc;
}, [])
Or Else any other easy solution is appreciated.
Thanks
Note that when you use Array#find, the result value will keep the reference. So when you change the content it will affect the array acc.
const testArray = [{key: 'a', value: 5}, {key: 'b', value: 1}, {key: 'a', value: 2}];
const result = testArray.reduce((acc, cur) => {
const exists = acc.find(item => item.key === cur.key)
if (!exists) acc.push(cur);
else exists.value -= cur.value;
return acc;
}, []);
console.log(result);
You can take advantage of Array.prototype.reduce combine with Array.prototype.findIndex to update the result array like this
const testArray = [{key: 'a', value: 5}, {key: 'b', value: 1}, {key: 'a', value: 2}]
let result = testArray.reduce((accumulator, current, index)=>{
let itemExists = accumulator.findIndex(item => {
return item.key == current.key;
});
if(itemExists !== -1){
current = {...current, value: accumulator[itemExists].value - current.value};
accumulator[itemExists] = current;
return accumulator;
} else {
return [...accumulator,current];
}
},[])
console.log(result);
The idea is when the current item doesn't exists in the result array we just add it to the array otherwhise we update the value of the existing one by updating It value key with the existing one value key minus the value key of the current item value
You can use Map where the keys are the key property from the objects and values are the entire object.
Now for every object in the testArray check if its key is present in the Map, if it is present, then update only the value, and it is not present set the entire value.
Solution Using Map
const testArray = [{ key: "a", value: 5 }, { key: "b", value: 1 }, { key: "a", value: 2 }];
const res = Array.from(testArray.reduce(
(m, o) => (
m.has(o.key)
? m.set(o.key, { ...m.get(o.key), value: m.get(o.key).value - o.value })
: m.set(o.key, { ...o }),
m
),
new Map()
).values());
console.log(res)
Same solution but in a more readable format
const testArray = [{ key: "a", value: 5 }, { key: "b", value: 1 }, { key: "a", value: 2 }];
const res = Array.from(testArray.reduce(
(m, o) => {
if (m.has(o.key)) {
const currVal = m.get(o.key);
m.set(o.key, {...currVal, value: currVal.value - o.value})
} else {
m.set(o.key, {...o})
}
return m;
},
new Map()
).values());
console.log(res)
One Liner Using Objects
If the key is not present in the object then create an object where the value property is double the actual value.
Now for every object, just subtract the current value with the already existing value.
const
testArray = [{ key: "a", value: 5 }, { key: "b", value: 1 }, { key: "a", value: 2 }],
res = testArray.reduce((m, {key, value}) => (m[key] ??= ((value) => ({key, value}))(2*value), m[key].value -= value, m), {});
console.log(Object.values(res))

How to use reduce to find maximum from array of objects with array of objects

If I have the following
arr = [
{key: "a",
values : [{key: "aa", value: 2}, {key: "bb", value: 5}]},
{key: "b",
values : [{key: "cc", value: 7}, {key: "dd", value: 3}]}
]
How to use reduce in javascript to find the maximum from the nested objects? The answer should be 7 in the above case.
I currently am able to use a loop to achieve this:
let max = 0;
let findDataMax = function(d) {
for (let i = 0; i < d.length; i++) {
let currArr = d[i].values;
let tempArr = []
currArr.forEach((d) => tempArr.push(+d.value));
if (Math.max(...tempArr) > max) {
max = Math.max(...tempArr);
}
}
}
let arr = [
{key: "a", values : [{key: "aa", value: 2}, {key: "bb", value: 5}]},
{key: "b",values : [{key: "cc", value: 7}, {key: "dd", value: 3}]}
];
findDataMax(arr);
console.log(max);
I would prefer to use other methods other than reduce for this, but if you have to, then you can set the accumulator as -Infinity to begin with (this way any value compared with the accumulator will be bigger than -Infinity). For each object in your array, you can find the max by mapping the array of values to an array of value numbers from each object, and then spreading these numbers into a call to Math.max(). You can then compare whether or not this is larger than the current maximum, and if it is, return that as the new value to use as the accumulator, otherwise, use the old accumulator value:
const arr = [ {key: "a", values : [{ key: "aa", value: 2}, { key: "bb",value: 5}]}, {key: "b", values : [{ key: "cc", value: 7}, { key: "dd", value: 3}]} ];
const max = arr.reduce((max, {values}) => {
const newMax = Math.max(...values.map(({value}) => value));
return newMax > max ? newMax : max;
}, -Infinity);
console.log(max);
As previously mentioned, I would probably use a different approach to .reduce(), such as .flatMap() to grab all object value numbers, which you can then spread into a call to Math.max():
const arr = [ {key: "a", values : [{ key: "aa", value: 2}, { key: "bb",value: 5}]}, {key: "b", values : [{ key: "cc", value: 7}, { key: "dd", value: 3}]} ];
const max = Math.max(...arr.flatMap(({values}) => values.map(({value}) => value)));
console.log(max);
I don't know if the use of the reduce function is a clean solution for this problem but here you have it:
const arr = [{ key: 'a', values: [{ key: 'aa', value: 2 }, { key: 'bb', value: 5 }] }, { key: 'b', values: [{ key: 'cc', value: 7 }, { key: 'dd', value: 3 }] }];
// O(n * b)
const maxValue = arr.reduce((prev, item) => item
.values.reduce((subPrev, subItem) => (subItem.value > subPrev ? subItem.value : subPrev), prev), 0);
console.log(maxValue); // 7

How to sort an object by value but still have access to the keys of the object in a mapping function?

Basically I have an object that looks like this.
var obj = {cat: "Cat",
dog: "Dog",
long: "Long",
modified_r: "Date Last",}
mal: "Mal"}`
What I want to do is map over the object and sort it by value but still have access to the keys of the object.
What I have at the moment is
let sorted = Object.entries(obj).sort().map((value) => {
return {value: value[0], label: value[1]}
});
This sorts the object by its Keys and then returns an array of objects like so.
0: {label: "cat", value: "Cat"}
1: {label: "dog", value: "Dog"}
2: {label: "long", value: "Long"}
3: {label: "mal", value: "Mal"}
4: {label: "modified_r", value: "Date Last"}
What I want to do is return an array of objects sorted in alphabetical order by its value like this.
0: {label: "cat", value: "Cat"}
1: {label: "modified_r", value: "Date Last"}
2: {label: "dog", value: "Dog"}
3: {label: "long", value: "Long"}
4: {label: "mal", value: "Mal"}
I have tried to map the object using Object.values(selectOptions).sort().map((value) => {}.
This sorts the objects by its values like how I want however I don't have access to the objects keys in this mapping function so I can't return the array of objects in the format that I want it.
What is the best way to map through an object sorting it by its values while still having access to the objects keys?
const obj = {
"key1": "value3",
"key2": "value2",
"key3": "value1"
}
let sortedByKey = Object.entries(obj).sort((a,b) => (a[0] < b[0]) ? -1 : 1).map((value) => {
return {label: value[0], value: value[1]}
});
let sortedByValue = Object.entries(obj).sort((a,b) => (a[1] < b[1]) ? -1 : 1).map((value) => {
return {label: value[0], value: value[1]}
});
console.log(sortedByKey);
console.log(sortedByValue);
You can use a comparator in the sort function to sort by value.
let sorted = Object.entries(obj).sort((a,b) => {
return a[1].localeCompare(b[1]);
}).map((value) => {
return {value: value[0], label: value[1]}
});

Javascript Replace item if key is duplicate and sort and delete except last 2 items

I have array like below , I want to sort it by key and then remove everything except last 2 items and delete remaining.
var status = new Array();
status.push({key: 'BOB', value: 10});
status.push({key: 'TOM', value: 3});
status.push({key: 'ROB', value: 22});
status.push({key: 'JON', value: 7});
If I again push below with duplicate key for example :
status.push({key: 'BOB', value: 20});
I need following output , how do i achieve this in javascript.
[
{
"key": "BOB",
"value": 20
},
{
"key": "TOM",
"value": 3
},
{
"key": "ROB",
"value": 22
},
{
"key": "JON",
"value": 7
}
]
Note : I need to sort this by key later.
Edit : If I have object like this , How do i sort by keys ? and get only last 2 items and delete remaining.
var status = new Object();
status['BOB'] = 10
status['TOM'] = 3
status['ROB'] = 22
status['JON'] = 7
I'd use a Map rather than an array or an object. Maps are like objects but with some important differences.
// initialize the map
var stats = new Map([['BOB',10],['TOM',3],['ROB',22],['JON',7]]);
// set a specific key's value
stats.set('BOB', 20);
// sort by key
var keys = Array.from(stats.keys());
keys.sort();
// get the last two
keys = keys.slice(-2);
// map the remaining keys to the desired structure
var result = keys.map(key => {
return {
key: key,
value: stats.get(key)
};
});
console.log(result);
Instead of using an array, use an object:
(function () {
var status = {};
status['BOB'] = 10;
status['TOM'] = 3;
status['ROB'] = 22;
status['JON'] = 7;
status['BOB'] = 20;
// convert to array
var output = Object.keys(status)
// sort by key
.sort()
// keep last two after sorting
.slice(-2)
// convert [key, value] to { key, value }
.map(function (key) {
return { key: key, value: status[key] };
});
console.log(output);
})();
.as-console-wrapper{max-height:100%!important}
In the case you decide to keep the array of objects structure, you can implement a method using Array.findIndex() and Array.splice() this way:
const pushWithCheck = (arr, obj) =>
{
let idx = arr.findIndex(({key}) => key === obj.key);
if (idx >= 0)
arr.splice(idx, 1, obj);
else
arr.push(obj);
}
var _status = [];
pushWithCheck(_status, {key: 'BOB', value: 10});
pushWithCheck(_status, {key: 'TOM', value: 3});
pushWithCheck(_status, {key: 'ROB', value: 22});
pushWithCheck(_status, {key: 'JON', value: 7});
console.log("Before duplicated key:", _status);
pushWithCheck(_status, {key: 'BOB', value: 20});
pushWithCheck(_status, {key: 'ROB', value: 99});
console.log("After duplicated key:", _status);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
Now, to sort by the key property of the objects and get last 2 elements, you can use Array.sort() and Array.slice() with a negative (-2) argument, like this:
const pushWithCheck = (arr, obj) =>
{
let idx = arr.findIndex(({key}) => key === obj.key);
if (idx >= 0)
arr.splice(idx, 1, obj);
else
arr.push(obj);
}
// Generate the _status array.
var _status = [];
pushWithCheck(_status, {key: 'BOB', value: 10});
pushWithCheck(_status, {key: 'TOM', value: 3});
pushWithCheck(_status, {key: 'ROB', value: 22});
pushWithCheck(_status, {key: 'JON', value: 7});
pushWithCheck(_status, {key: 'BOB', value: 20});
pushWithCheck(_status, {key: 'ROB', value: 99});
console.log("_status is: ", _status);
// Sort the _status array by ascending.
let sorted = _status.slice().sort((a, b) => a.key.localeCompare(b.key));
// Get last two elements of the sorted array.
let lastTwo = sorted.slice(-2);
console.log("Sorted is: ", sorted);
console.log("Last two elements are: ", lastTwo);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
if you want to do it the way others are suggesting you should use a set set always have unique elements in them
// initialize the map
var stats = new Set([['BOB',10],['TOM',3],['ROB',22],['JON',7]]);
// set a specific key's value
stats.add('BOB', 20);
// sort by key
var keys = Array.from(stats.keys());
keys.sort();
// get the last two
keys = keys.slice(-2);
// map the remaining keys to the desired structure
var result = keys
console.log(result);
I think this answers all your questions
let status1 = [];
status1.push({
key: 'BOB',
value: 10
}, {
key: 'TOM',
value: 3
}, {
key: 'ROB',
value: 22
}, {
key: 'JON',
value: 7
});
console.log('Initial array', status1);
//const newItem = {
// key: 'BOB',
// value: 20
//};
const newItem = {
key: 'BOB',
value: 99
};
for (let i = 0; i < status1.length; i++) {
if (status1[i].key === newItem.key) {
status1[i] = newItem;
}
}
Array.prototype.inArray = function(comparer) {
for(var i=0; i < this.length; i++) {
if(comparer(this[i])) return true;
}
return false;
};
Array.prototype.pushIfNotExist = function(element, comparer) {
if (!this.inArray(comparer)) {
this.push(element);
}
};
//https://stackoverflow.com/questions/1988349/array-push-if-does-not-exist
status1.pushIfNotExist(newItem, function(e) {
return e.key === newItem.key;
});
console.log('after push', status1);
function sortByKey(array, key) {
return array.sort(function (a, b) {
var x = a[key];
var y = b[key];
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});
}
sortByKey(status1, 'key');
console.log('AFter sort', status1);
console.log('Last item', status1[status1.length - 1]);
console.log('Second Last item', status1[status1.length - 2]);

Categories