Filter array of object with conditions - javascript

I would like to filter an array of objects according to the highest value of "value" key and distinct each object by their "id" key.
Example :
var array = [
{
id: 1,
value: 10
},
{
id: 1,
value: 2
},
{
id: 2,
value: 6
},
{
id: 2,
value: 5
},
{
id: 2,
value: 1
}
]
And the expected output:
array = [
{
id: 1,
value: 10
},
{
id: 2,
value: 6
}
]
Thanks

You could reduce the array and check if an object exist with the same id and update if necessary. This approach takes the objects with the largest value.
const
array = [{ id: 1, value: 10 }, { id: 1, value: 2 }, { id: 2, value: 6 }, { id: 2, value: 5 }, { id: 2, value: 1 }],
result = array.reduce((r, o) => {
const index = r.findIndex(({ id }) => o.id === id);
if (index === -1) r.push(o);
else if (r[index].value < o.value) r[index] = o;
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Another approach with a Map.
const
array = [{ id: 1, value: 10 }, { id: 1, value: 2 }, { id: 2, value: 6 }, { id: 2, value: 5 }, { id: 2, value: 1 }],
result = Array.from(
array.reduce((m, { id, value }) => m.set(id, m.has(id)
? Math.max(m.get(id), value)
: value
), new Map),
([id, value]) => ({ id, value })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Here is a possible way to doing this
var array = [
{
id: 1,
value: 10
},
{
id: 1,
value: 2
},
{
id: 2,
value: 6
},
{
id: 2,
value: 5
},
{
id: 2,
value: 1
}
]
let objdis = {};
array.forEach(val => {
if(objdis[val.id] !== undefined){
objdis[val.id].push(Number(val.value));
}else{
objdis[val.id] = [];
objdis[val.id].push(val.value);
}
})
let returningObj = [];
for (prop in objdis){
let obj = {};
obj.id = Number(prop);
obj.Value = Math.max(...objdis[prop])
returningObj.push(obj);
}
console.log(returningObj);

i hope this helps
var arr = [
{
id: 1,
value: 10
},
{
id: 1,
value: 2
},
{
id: 2,
value: 6
},
{
id: 2,
value: 5
},
{
id: 2,
value: 1
}
];
const output = Object.values(arr.reduce((x, y) => {
x[y.id] = x[y.id] && x[y.id].value > y.value ? x[y.id] : y
return x
}, {}));
console.log(output);

There's my answer, but it needs to have sorted indexes and isn't as cool as reduce examples You got here.
var array = [
{
id: 1,
value: 10
},
{
id: 1,
value: 1
},
{
id: 2,
value: 1
},
{
id: 2,
value: 5
},
{
id: 2,
value: 35
},
{
id: 3,
value: 4
},
{
id: 3,
value: 14
},
{
id: 2,
value: 123
}
];
function getHighestValues(Arr) {
var newArr = [];
var IdArr = Arr.map(elem => elem.id);
IdArr.sort((a,b)=>a-b);
for(var i = 0; i < Arr.length; i++) {
let currIdIndex = IdArr.indexOf(Arr[i].id);
if(newArr[currIdIndex] == undefined) {
newArr.push(
{
id: Arr[i].id,
value: Arr[i].value
})
} else if(newArr[currIdIndex].value < Arr[i].value) {
newArr[currIdIndex].value = Arr[i].value;
}
IdArr.splice(currIdIndex, 1);
if(IdArr.indexOf(Arr[i].id) == -1) {
IdArr.splice(currIdIndex, 0, Arr[i].id);
}
}
return newArr;
}
array = getHighestValues(array);
console.log(array);

Related

nested for loops to get another object-array output

I need to multiply all the "values" inside "obj1" with the "percent' inside obj2 based on the id of each object. What would be the best way to do that? I've tried with for loop and reduce but I wasn't successful. Any help will be appreciated.
const obj1 = [ { id: 1, value: 10 }, { id: 2, value: 10 } ]
const obj2 = {
len: {
id: 1,
nj: "321345",
percent: 0.05,
},
wor: {
id: 2,
nj: "321345",
percent: 0.1,
}
}
outputExpected: [ { id: 1, value: 0.5 }, { id: 2, value: 1 } ]
You can do that by going through and matching the ids. there are some optimizations that can be made if they are sorted however.
const obj1 = [ { id: 1, value: 10 }, { id: 2, value: 10 } ]
const obj2 = {
len: {
id: 1,
nj: "321345",
percent: 0.05,
},
wor: {
id: 2,
nj: "321345",
percent: 0.1,
}
}
const x = Object.keys(obj2).map((key,index)=>{
const { id, value } = obj1.find(({id})=>id===obj2[key].id)
return ({id,value:value*obj2[key].percent})
})
console.log(x)
//outputExpected: [ { id: 1, value: 0.5 }, { id: 2, value: 1 } ]
You can first create a lookup map using Map, then loop over the obj1 using map to get the desired result
const obj1 = [
{ id: 1, value: 10 },
{ id: 2, value: 10 },
];
const obj2 = {
len: {
id: 1,
nj: "321345",
percent: 0.05,
},
wor: {
id: 2,
nj: "321345",
percent: 0.1,
},
};
const map = new Map();
Object.values(obj2).forEach((v) => map.set(v.id, v));
const result = obj1.map((o) => ({ ...o, value: o.value * map.get(o.id).percent }));
console.log(result);
This should work for you but doesnt handle exeptions if the id doesnt exist in both objects.
// First get the values in an array for easier manipulation
const aux = Object.values(obj2)
const output = obj1.map(ob => {
// Find the id in the other array.
const obj2Ob = aux.find(o => o.id === ob.id) // The id must exist in this aproach
return {
id: ob.id,
value: ob.value * obj2Ob.percent
}
})
console.log(output) // [ { id: 1, value: 0.5 }, { id: 2, value: 1 } ]

Update the value of nested object in the array based on the key

i have two array of objects like below, am trying to compare two arrays and looking to update the object total value of arr1 if the id matches with arr2.
const arr1 = [
{
id: 1,
value: { total: 0 },
},
{
id: 2,
value: { total: 0 },
},
{
id: 3,
value: { total: 0 },
},
id: 4,
value: { total: 0 },
},
];
const arr2 = [
{
id: 2,
value: 3 ,
},
{
id: 3,
value: 5,
},
];
I am trying to compare two arrays and looking to update the object total value of arr1 if the id matches with arr2
expected result is
const arr1 = [
{
id: 1,
value: { total: 0 },
},
{
id: 2,
value: { total: 3 },
},
{
id: 3,
value: { total: 5 },
},
{
id: 4,
value: { total: 0 },
},
];
I have tried the below code,
arr1.map((item) => {
arr2.find((element) => {
if (element.id === item.id ) {
item = {
...item,
value: {
...item.value,
total: item.value.total + element.value,
},
};
console.log(item);
}
});
return item;
});
I have changed the find function to the filter function and will add the result to the original array.
try this
const arr1 = [
{
id: 1,
value: { total: 0 },
},
{
id: 2,
value: { total: 0 },
},
{
id: 3,
value: { total: 0 },
},
{
id: 4,
value: { total: 0 },
}
]
const arr2 = [
{
id: 2,
value: 3 ,
},
{
id: 3,
value: 5,
},
];
arr1.map((item) => {
let result = arr2.filter((element) => element.id == item.id)
if(result && result.length) {
item.value.total += result[0].value
}
return item;
});
console.log(arr1)
You have to assign map to your array:
this.arr1 = this.arr1.map((item) => {
this.arr2.find((element) => {
if (element.id === item.id) {
item = {
...item,
value: {
...item.value,
total: item.value.total + element.value,
},
};
console.log(item);
}
});
return item;
});
If each object's id is unique (within each array), you can do:
arr1.forEach((obj1) => {
const obj2Match = arr2.find((obj2) => obj1.id === obj2.id );
if (obj2Match) {
obj1.value.total += obj2Match.value;
}
});
If more than one object can have the same id (e.g. arr2 has two objects that have the id of 2), then you can do:
arr1.forEach((obj1) => {
const obj2Matches = arr2.filter((obj2) => obj1.id === obj2.id );
if (obj2Matches.length) {
obj1.value.total += obj2Matches.reduce(((accum, curr) => accum + curr.value), 0);
}
});
Complexity:
Time: O(N * M)
Space: O(M)
N => arr1.length, M => arr2.length
You could do something like this:
arr2.map((x) => {
let result = arr1.filter((a1) => a1.id === x.id);
if (result.length > 0) {
x.total = result[0].total;
}
return x;
});

Sort array and SUM item counts [duplicate]

I have javascript array object as below. My need is to sum value base on seach id in the array object.
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
],
For example sum of value for id 1 is 10 + 30 + 25 + 20 = 85 , It may be something link linq but I'm not sure in javascript. Thanks for all answers.
You can use a combination of filter and reduce to get the result you want:
sumOfId = (id) => array.filter(i => i.id === id).reduce((a, b) => a + b.val, 0);
Usage:
const sumOf1 = sumOfId(1); //85
Reading material:
Array.prototype.filter
Array.prototype.reduce
A way to do it with a traditional for loop
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
var sums = {};
for (var i = 0; i < array.length; i++) {
var obj = array[i];
sums[obj.id] = sums[obj.id] === undefined ? 0 : sums[obj.id];
sums[obj.id] += parseInt(obj.val);
}
console.log(sums);
running example
You can use reduce() and findIndex()
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
let res = array.reduce((ac,a) => {
let ind = ac.findIndex(x => x.id === a.id);
ind === -1 ? ac.push(a) : ac[ind].val += a.val;
return ac;
},[])
console.log(res);
JS noob here ... I guess something like this should be here too :-)
let newArray = {}
array.forEach((e) => {
!newArray[e.id] && (newArray[e.id] = 0);
newArray[e.id] += e.val;
});
You can loop on the array and check the ids.
var array = [
{ id: 1, val: 10 },
{ id: 2, val: 25 },
{ id: 3, val: 20 },
{ id: 1, val: 30 },
{ id: 1, val: 25 },
{ id: 2, val: 10 },
{ id: 1, val: 20 }
];
var sum = 0;
var id = 1;
$.each(array, function(index, object){
if (object.id == id) {
sum += object.val;
}
});
console.log(sum);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Using Array#reduce and Map you can get the sum for each id like so. This also uses destructuring to have quicker access to properties.
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
console.log(res.get(1));
console.log(res.get(2));
If you wanted to output all the sums, then you need to use Array#from
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = Array.from(
data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
);
console.log(res);
If the format should be similar as to your original structure, you need to add a Array#map afterwards to transform it.
const data=[{id:1,val:10},{id:2,val:25},{id:3,val:20},{id:1,val:30},{id:1,val:25},{id:2,val:10},{id:1,val:20}];
const res = Array.from(
data.reduce((a,{id,val})=>{
return a.set(id, (a.get(id)||0) + val);
}, new Map())
).map(([id,sum])=>({id,sum}));
console.log(res);
You could take GroupBy from linq.js with a summing function.
var array = [{ id: 1, val: 10 }, { id: 2, val: 25 }, { id: 3, val: 20 }, { id: 1, val: 30 }, { id: 1, val: 25 }, { id: 2, val: 10 }, { id: 1, val: 20 }],
result = Enumerable
.From(array)
.GroupBy(null, null, "{ id: $.id, sum: $$.Sum('$.val') }", "$.id")
.ToArray();
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.js"></script>
Here is another option, introducing an Array.prototype.sum helper:
Array.prototype.sum = function (init = 0, fn = obj => obj) {
if (typeof init === 'function') {
fn = init;
init = 0;
}
return this.reduce(
(acc, ...fnArgs) => acc + fn(...fnArgs),
init
);
};
// .sum usage examples
console.log(
// sum simple values
[1, 2, 3].sum(),
// sum simple values with initial value
[1, 2, 3].sum(10),
// sum objects
[{ a: 1 }, { a: 2 }, { a: 3 }].sum(obj => obj.a),
// sum objects with initial value
[{ a: 1 }, { a: 2 }, { a: 3 }].sum(10, obj => obj.a),
// sum custom combinations
[{ amount: 1, price: 2 }, { amount: 3, price: 4 }]
.sum(product => product.amount * product.price)
);
var array = [{ id: 1, val: 10 }, { id: 2, val: 25 }, { id: 3, val: 20 }, { id: 1, val: 30 }, { id: 1, val: 25 }, { id: 2, val: 10 }, { id: 1, val: 20 }];
// solutions
console.log(
array.filter(obj => obj.id === 1).sum(obj => obj.val),
array.filter(({id}) => id === 1).sum(({val}) => val),
array.sum(({id, val}) => id === 1 ? val : 0)
);
references:
Array.prototype.reduce
Array.prototype.filter
Arrow functions used in sum(obj => obj.val)
Object destructing assignment used in ({id}) => id === 1
Rest parameters used in (acc, ...fnArgs) => acc + fn(...fnArgs)
Conditional (ternary) operator used in id === 1 ? val : 0

check the difference between two arrays of objects in javascript [duplicate]

This question already has answers here:
How to get the difference between two arrays of objects in JavaScript
(22 answers)
Closed 1 year ago.
I need some help. How can I get the array of the difference on this scenario:
var b1 = [
{ id: 0, name: 'john' },
{ id: 1, name: 'mary' },
{ id: 2, name: 'pablo' },
{ id: 3, name: 'escobar' }
];
var b2 = [
{ id: 0, name: 'john' },
{ id: 1, name: 'mary' }
];
I want the array of difference:
// [{ id: 2, name: 'pablo' }, { id: 3, name: 'escobar' }]
How is the most optimized approach?
I´m trying to filter a reduced array.. something on this line:
var Bfiltered = b1.filter(function (x) {
return x.name !== b2.reduce(function (acc, document, index) {
return (document.name === x.name) ? document.name : false
},0)
});
console.log("Bfiltered", Bfiltered);
// returns { id: 0, name: 'john' }, { id: 2, name: 'pablo' }, { id: 3, name: 'escobar' } ]
Thanks,
Robot
.Filter() and .some() functions will do the trick
var b1 = [
{ id: 0, name: 'john' },
{ id: 1, name: 'mary' },
{ id: 2, name: 'pablo' },
{ id: 3, name: 'escobar' }
];
var b2 = [
{ id: 0, name: 'john' },
{ id: 1, name: 'mary' }
];
var res = b1.filter(item1 =>
!b2.some(item2 => (item2.id === item1.id && item2.name === item1.name)))
console.log(res);
You can use filter to filter/loop thru the array and some to check if id exist on array 2
var b1 = [{ id: 0, name: 'john' }, { id: 1, name: 'mary' }, { id: 2, name: 'pablo' }, { id: 3, name: 'escobar' } ];
var b2 = [{ id: 0, name: 'john' }, { id: 1, name: 'mary' }];
var result = b1.filter(o => !b2.some(v => v.id === o.id));
console.log(result);
Above example will work if array 1 is longer. If you dont know which one is longer you can use sort to arrange the array and use reduce and filter.
var b1 = [{ id: 0, name: 'john' }, { id: 1, name: 'mary' }, { id: 2, name: 'pablo' }, { id: 3, name: 'escobar' } ];
var b2 = [{ id: 0, name: 'john' }, { id: 1, name: 'mary' }];
var result = [b1, b2].sort((a,b)=> b.length - a.length)
.reduce((a,b)=>a.filter(o => !b.some(v => v.id === o.id)));
console.log(result);
Another possibility is to use a Map, allowing you to bring down the time complexity to O(max(n,m)) if dealing with a Map-result is fine for you:
function findArrayDifferences(arr1, arr2) {
const map = new Map();
const maxLength = Math.max(arr1.length, arr2.length);
for (let i = 0; i < maxLength; i++) {
if (i < arr1.length) {
const entry = arr1[i];
if (map.has(entry.id)) {
map.delete(entry.id);
} else {
map.set(entry.id, entry);
}
}
if (i < arr2.length) {
const entry = arr2[i];
if (map.has(entry.id)) {
map.delete(entry.id);
} else {
map.set(entry.id, entry);
}
}
}
return map;
}
const arr1 = [{id:0,name:'john'},{id:1,name:'mary'},{id:2,name:'pablo'},{id:3,name:'escobar'}];
const arr2 = [{id:0,name:'john'},{id:1,name:'mary'},{id:99,name:'someone else'}];
const resultAsArray = [...findArrayDifferences(arr1,arr2).values()];
console.log(resultAsArray);

How to create a multidimensional array from normal array

I have a json array after the form submission using formSerialize function like this
[
{"name":"client_management-testmonitoring","value":"0"},
{"name":"client_operations-testmonitoring","value":"0"},
{"name":"tpl_management-testmonitoring","value":"0"},
{"name":"tpl_operations-testmonitoring","value":"0"},
{"name":"channel_partner-testmonitoring","value":"0"},
{"name":"operator-testmonitoring","value":"0"},
{"name":"financier-testmonitoring","value":"0"},
{"name":"client_management-test_monitoring_2","value":"0"},
{"name":"client_operations-test_monitoring_2","value":"0"},
{"name":"tpl_management-test_monitoring_2","value":"0"},
{"name":"tpl_operations-test_monitoring_2","value":"0"},
{"name":"channel_partner-test_monitoring_2","value":"0"},
{"name":"operator-test_monitoring_2","value":"0"},
{"name":"financier-test_monitoring_2","value":"0"},
{"name":"client_management-test_monitoring_3","value":"0"},
{"name":"client_operations-test_monitoring_3","value":"0"},
{"name":"tpl_management-test_monitoring_3","value":"0"},
{"name":"tpl_operations-test_monitoring_3","value":"0"},
{"name":"channel_partner-test_monitoring_3","value":"0"},
{"name":"operator-test_monitoring_3","value":"0"},
{"name":"financier-test_monitoring_3","value":"0"}
]
and i need to convert this array like this :
[
{
"role": [
{
"role_name": "client_management",
"report_name": [
{
"test_monitoring_1": 1,
"test_monitoring_2": 1,
"test_monitoring_3": 0
}
]
}
]
},
{
"role": [
{
"role_name": "financier",
"report_name": [
{
"test_monitoring_1": 1,
"test_monitoring_2": 0,
"test_monitoring_3": 1
}
]
}
]
}
]
am trying this code to get the multidimesional array.
var formData = $('#' + reportType).serializeArray(),matrix_array =[];
for (var u = 0; u < formData.length; u++) {
for (var user in formData[u])
{
if (user == 'name') {
var matrix_name_n = formData[u][user],
matrix_name_a = matrix_name_n.split('-'),
role_name = matrix_name_a[0],
parameter_name = matrix_name_a[1];
var matrix_array_2 = [];
}
if (user == 'value') {
var matrix_param_value = formData[u][user], matrix_array_3 = [matrix_param_value];
}
}
var matrix_array2 = {};
var matrix_array2 = {};
matrix_array2["role"] = role_name;
matrix_array2[parameter_name] = matrix_param_value;
matrix_array_2.push(matrix_array2);
matrix_array.push(matrix_array_2);
var insert_matrix = {};
insert_matrix = JSON.stringify(formData);
}
but am not getting the expected result.Please help someone to sort out this issue
You could split the name by minus sign and use the first part as role_name and the second part as report_name property of the inner object.
var data = [{ name: "client_management-testmonitoring", value: 0 }, { name: "client_operations-testmonitoring", value: 0 }, { name: "tpl_management-testmonitoring", value: 0 }, { name: "tpl_operations-testmonitoring", value: 0 }, { name: "channel_partner-testmonitoring", value: 0 }, { name: "operator-testmonitoring", value: 0 }, { name: "financier-testmonitoring", value: 0 }, { name: "client_management-test_monitoring_2", value: 0 }, { name: "client_operations-test_monitoring_2", value: 0 }, { name: "tpl_management-test_monitoring_2", value: 0 }, { name: "tpl_operations-test_monitoring_2", value: 0 }, { name: "channel_partner-test_monitoring_2", value: 0 }, { name: "operator-test_monitoring_2", value: 0 }, { name: "financier-test_monitoring_2", value: 0 }, { name: "client_management-test_monitoring_3", value: 0 }, { name: "client_operations-test_monitoring_3", value: 0 }, { name: "tpl_management-test_monitoring_3", value: 0 }, { name: "tpl_operations-test_monitoring_3", value: 0 }, { name: "channel_partner-test_monitoring_3", value: 0 }, { name: "operator-test_monitoring_3", value: 0 }, { name: "financier-test_monitoring_3", value: 0 }],
result = data.reduce(function (hash) {
return function (r, a) {
var parts = a.name.split('-');
if (!hash[parts[0]]) {
hash[parts[0]] = {};
r[0].role.push({ role_name: parts[0], report_name: [hash[parts[0]]] });
}
if (!parts[1].match(/\d$/)) {
parts[1] = 'test_monitoring_1';
}
hash[parts[0]][parts[1]] = a.value;
return r;
}
}(Object.create(null)), [{ report_name: "monitoring", role: [] }]);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories

Resources