In javascript, need to perform sum of dynamic array - javascript

I have a dynamic array and I need to perform a sum of it.
{ClientName: "A", Alex: 2, Da: 0, Cal: 0}
{ClientName: "b", Alex: 0, Da: 0, Cal: 4}
{ClientName: "c", Alex: 1, Da: 0, Cal: 5}
{ClientName: "d", Alex: 2, Da: 0, Cal: 0}
in this array, client name is fixed but other columns like Alex, Da, Cal are dynamic and will vary. i need to create a generic function in typescript where output will be like this.
{ClientName: "Total", Alex: 5, Da: 0, Cal: 9}

You can try something like this:
Idea:
Uses Object.keys to get all enumerable keys.
Loop over them ans set them to default if not found. Then add current object's value.
Since you need hardcoded value for ClientName, you can set it either in loop or set it after loop.
const data = [
{ClientName: "A", Alex: 2, Da: 0, Cal: 0},
{ClientName: "b", Alex: 0, Da: 0, Cal: 4},
{ClientName: "c", Alex: 1, Da: 0, Cal: 5},
{ClientName: "d", Alex: 2, Da: 0, Cal: 0},
]
const output = data.reduce((acc, item) => {
Object
.keys(item)
.forEach((key) => {
acc[key] = (acc[key] || 0) + item[key]
});
acc.ClientName = 'Total'
return acc;
}, {})
console.log(output)

You could reduce the wanted values.
var data = [{ ClientName: "A", Alex: 2, Da: 0, Cal: 0 }, { ClientName: "b", Alex: 0, Da: 0, Cal: 4 }, { ClientName: "c", Alex: 1, Da: 0, Cal: 5 }, { ClientName: "d", Alex: 2, Da: 0, Cal: 0 }],
total = data.reduce((a, { ClientName, ...b }) => Object.assign(
{},
a,
{ ClientName: 'total' },
...Object.entries(b).map(([k, v]) => ({ [k]: (a[k] || 0) + v }))
));
console.log(total);

Something along these lines should work as long as all keys besides ClientName are defined as numbers
arr.reduce((sumObject, item) => {
Object.keys(item).forEach(key => {
if(key === 'ClientName'){
return false
}
if(!sumObject[key]) {
sumObject[key] = item[key]
} else {
sumObject[key] += item[key]
}
})
return sumObject
}, {ClientName: 'Total'})

You can iterate with reduce to generate single output and to merge the key count you can use Object.keys and map will allow you to iterate over your object keys. Also added one dynamic key Abc: 9 just to verify the result.
const object = [{
ClientName: "A",
Alex: 2,
Da: 0,
Cal: 0
},
{
ClientName: "b",
Alex: 0,
Da: 0,
Cal: 4
},
{
ClientName: "c",
Alex: 1,
Da: 0,
Cal: 5
},
{
ClientName: "d",
Alex: 2,
Da: 0,
Cal: 0,
Abc: 9
},
]
const result = object.reduce((accumulator, currentValue) => {
Object.keys(currentValue).map((indexKey) => {
accumulator[indexKey] = (accumulator[indexKey] || 0) + currentValue[indexKey]
});
accumulator.ClientName = "Total";
return accumulator;
})
console.log(result);

let arr = [
{ClientName: "A", Alex: 2, Da: 0, Cal: 0},
{ClientName: "b", Alex: 0, Da: 0, Cal: 4},
{ClientName: "c", Alex: 1, Da: 0, Cal: 5},
{ClientName: "d", Alex: 2, Da: 0, Cal: 0}
];
let output = arr.reduce((curr, next) => {
return {ClientName: "Total", Alex: (curr.Alex + next.Alex ), Da: (curr.Da + next.Da), Cal: (curr.Cal + next.Cal)};
});
console.log(output);
Check this can get the answer simply

Related

Comparing values of objects in array and making operation on them

I'm trying to compare same field elements in objects and restructuring them. I tried to use filter, sort methods but couldn't achieve that. I have an array like this:
const data = [
{
id: 1,
direction: "A",
carry: 6,
distance: 1.41,
},
{
id: 2,
direction: "B",
carry: 5,
distance: 2.83,
},
{
id: 3,
direction: "C",
carry: 4,
distance: 4.24,
},
{
id: 4,
direction: "D",
carry: 3,
distance: 5.66,
},
];
For example: Let's take distance field, they are 1.41, 2.83, 4.24, 5.66. The biggest value (5.66) will be 100%, and other values can be calculated like proportion.
5.66 -> 100%
1.41 -> 25%
2.83 -> 50%
4.24 -> 75%
The carry field follows this way as well. The final result should be like that:
const data = [
{
id: 1,
direction: "A",
carry: 6,
carry_rating: 100,
distance: 1.41,
distance_rating: 25,
},
{
id: 2,
direction: "B",
carry: 5,
carry_rating: 84,
distance: 2.83,
distance_rating: 50,
},
{
id: 3,
direction: "C",
carry: 4,
carry_rating: 67,
distance: 4.24,
distance_rating: 75,
},
{
id: 4,
direction: "D",
carry: 3,
carry_rating: 50
distance: 5.66,
distance_rating: 100,
},
];
I'm struggling for several days. Any support is much appreciated.
A simple way of doing this is to first find the maximum values for distance and carry. Can do this in 1 iteration using array reduce. After that use an array map to add the new fields.
const data = [ { id: 1, direction: "A", carry: 6, distance: 1.41, }, { id: 2, direction: "B",carry: 5, distance: 2.83,}, { id: 3, direction: "C", carry: 4, distance: 4.24, }, { id: 4, direction: "D", carry: 3, distance: 5.66, },];
const {maxCarry,maxDistance} = data.reduce((acc,{carry,distance}) => {
acc.maxCarry = carry < acc.maxCarry ? acc.maxCarry : carry
acc.maxDistance = distance < acc.maxDistance ? acc.maxDistance : distance
return acc
}, {maxCarry:0,maxDistance:0})
const res = data.map((e) => {
const carry_rating = Math.ceil((e.carry/maxCarry)*100)
const distance_rating = Math.ceil((e.distance/maxDistance)*100)
return {carry_rating,distance_rating,...e}
})
console.log(res)
const data = [
{
id: 1,
direction: "A",
carry: 6,
distance: 1.41,
},
{
id: 2,
direction: "B",
carry: 5,
distance: 2.83,
},
{
id: 3,
direction: "C",
carry: 4,
distance: 4.24,
},
{
id: 4,
direction: "D",
carry: 3,
distance: 5.66,
},
];
const maxDistance = Math.max(...data.map(obj => obj.distance))
console.log(maxDistance)
const results = data.map(obj => ({ ...obj, distance_rating: Math.round((obj.distance / maxDistance) * 100) }))
console.log(results)

Javascript get largest object in array of objects

I want to get the largest object in an array of objects, the code I'm using works fine, but I wonder if there is a better way of doing the same. This is the code I'm using.
data=[
{group: "a", A: 65, N: 20},
{group: "b", R: 52},
{group: "c", N: 20, A: 2, R: 2},
{group: "d", R: 15, N: 12},
]
len = []
for (var i in data){
len.push(Object.keys(data[i]).length)
}
for (var i in data){
if (Object.keys(data[i]).length==Math.max.apply(null, len)){
subgroups = Object.keys(data[i]).slice(1).sort();
}
}
console.log(subgroups);
I think one loop is sufficient to do this.
var data=[
{group: "a", A: 65, N: 20},
{group: "b", R: 52},
{group: "c", N: 20, A: 2, R: 2},
{group: "d", R: 15, N: 12},
],
max = Object.keys(data[0]).length,
largestObj = data[0];
data.forEach(i=>{
if(Object.keys(i).length> max){
max = Object.keys(i).length;
largestObj = i;
}
});
console.log(max);
console.log(largestObj);
An example using Array.prototype.reduce
const [biggestObject] = data.reduce(
([acc, length], entry) => {
const len = Object.keys(entry).length;
return length > len ? [acc, length] : [entry, len];
},
[{}, 0]
);
To sort the whole array seems stupid, one loop is enough using reduce function
const { element } = data.reduce((agg, element) => {
const length = Object.keys(v).length
if (length > agg.length) {
return { element, length }
}
return agg
}, { element: null, length: 0 })
You can just sort the array using the criteria you used for filling the len array.
data.sort((x, y) => {
return Object.keys(y).length - Object.keys(x).length
});
Result:
0: {group: "c", N: 20, A: 2, R: 2}
1: {group: "a", A: 65, N: 20}
2: {group: "d", R: 15, N: 12}
3: {group: "b", R: 52}

How to combine two array using ramda library?

I have two array as below
const l1 = [ {"a": 1, "a1": 2}, {"b": 3, "b1": 4}, {"c": 5, "c1": 6} ];
const l2 = [ {"d": 2}, {"e": 2}, {"f": 2} ];
How can I use ramda library to combine these two and get result like
[ {"a": 1, "a1": 2, "d": 2}, {"a": 1, "a1": 2, "e": 2}, {"a": 1, "a1": 2, "f": 2},
{"b": 3, "b1": 4, "d": 2}, {"b": 3, "b1": 4, "e": 2}, {"b": 3, "b1": 4, "f": 2},
{"c": 5, "c1": 6, "d": 2}, {"c": 5, "c1": 6, "e": 2}, {"c": 5, "c1": 6, "f": 2} ]
I used
R.map(R.xprod(__, l2, l1)
But not working since i got object inside array.
Thanks in advance.
To get a Cartesian product of two arrays of objects you can create a function by lifting merge:
const fn = R.lift(R.merge)
const l1 = [ {"a": 1, "a1": 2}, {"b": 3, "b1": 4}, {"c": 5, "c1": 6} ];
const l2 = [ {"d": 2}, {"e": 2}, {"f": 2} ];
const result = fn(l1, l2)
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js" integrity="sha256-buL0byPvI/XRDFscnSc/e0q+sLA65O9y+rbF+0O/4FE=" crossorigin="anonymous"></script>
If not very particular about ramda, you can do as below with one line using flatMap and map.
const l1 = [
{ a: 1, a1: 2 },
{ b: 3, b1: 4 },
{ c: 5, c1: 6 }
];
const l2 = [{ d: 2 }, { e: 2 }, { f: 2 }];
const merged = l2.flatMap(item2 => l1.map(item1 => ({ ...item1, ...item2 })));
console.log(JSON.stringify(merged));
With plain Javascript, you could take cartesian product with a double nested reduce by mapping new objects.
This approach works for an arbirary count of arrays (sort of ...).
const
l1 = [{ a: 1, a1: 2 }, { b: 3, b1: 4 }, { c: 5, c1: 6 }],
l2 = [{ d: 2 }, { e: 2 }, { f: 2 }],
result = [l1, l2].reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => ({ ...v, ...w }))), []));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
There is another option to merge arrays using R.reduce function
const input = {
arr1: ['a', 'b'],
arr2: ['c', 'd']
}
R.compose(
R.reduce((acc, cur) => {
return [...acc, ...cur]
}, []),
R.map(([key, value]) => value),
R.toPairs
)(input)

Sorting an array based on property value of another array of objects

Let's say I have an array of objects:
var list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
if I have another array like this one :
var disturbed = ["G", "B", "C", "F"];
how can I sort disturbed array based on distance property from the list array like this:
["B", "C", "F", "G"];
Edit: I have tried this code with no success:
items = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
]
sorting = [ 1, 2,3,4,5,6,7,8,9,10 ];
result = []
for (let i = 0; i < items.length; i++){
sorting.forEach(function(key) {
var found = false;
items = items.filter(function(item) {
if(!found && items[i].distance == key) {
result.push(item);
found = true;
return false;
} else
return true;
})
})
result.forEach(function(item) {
document.writeln(item[i])
})
}
How can I Sort an array based on the property value of another array of objects
You can use .reduce() to change the list array to object and then sort based on this object.
Demo:
var list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
var disturbed = ["G", "B", "C", "F"];
var sort = list.reduce((acc, cur) => {
acc[cur.name] = cur.distance;
return acc;
}, {});
disturbed.sort((a, b) => sort[a] - sort[b]);
console.log(disturbed)
You can use the sort method to do that
var list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
var disturbed = ["G", "B", "C", "F"];
disturbed.sort((a, b) => {
var itemA = list.find(item => item.name === a);
var itemB = list.find(item => item.name === b);
return itemA.distance - itemB.distance;
});
disturbed.forEach(function(item) {
document.writeln(item[i])
})
You can use .find() to find the object with the specified name property that matches your elements in distributed. Once you have got this you can then get the distance property and calculate the difference to sort accordingly:
const list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
const disturbed = ["G", "B", "C", "F"];
const res = disturbed.sort((a, b) => {
const {distance: d_a} = list.find(({name}) => name === a);
const {distance: d_b} = list.find(({name}) => name === b);
return d_a - d_b;
});
console.log(res);
A more efficient approach would be to create a new Map using .map() and then use .sort() on the keys form the map:
const list = [
{ name: "A", distance: 1},
{ name: "B", distance: 2},
{ name: "C", distance: 3},
{ name: "D", distance: 4},
{ name: "E", distance: 5},
{ name: "F", distance: 6},
{ name: "G", distance: 7},
{ name: "H", distance: 8}
];
const disturbed = ["G", "B", "C", "F"];
const lut = new Map(list.map(({name, distance}) => [name, distance]));
const res = disturbed.sort((a, b) => lut.get(a) - lut.get(b));
console.log(res);

Use dictionary to filter javascript data object

Say I have a filter:
filter = [ {key: "pl", value: 3}, {key: "sh", value: 2} ]
I want to filter the following javascript object with the above filter conditions:
var data = [
{title: "The Uncertainty of the Poet ",
pl: 3,
si: 2,
va: 3,
te: 0,
co: 0,
or: 4,
sh: 2,
po: 0,
li: 0,
ar: 5
},
{
title: "Direction",
pl: 4,
si: 3,
va: 1,
te: 3,
co: 0,
or: 3,
sh: 2,
po: 0,
li: 0,
ar: 5
}
...
]
I tried the following with no luck:
var result = data.filter(function(d){
for (item in filter) {
return d.key==d.value;
}
Just another potential option to check if the object meets all the criteria:
data.filter(function(obj) {
return filter.reduce(function(a, f) {
return a && (obj[f.key] === f.value);
}, true);
});
That will work without having to check for hasOwnProperty because of the use of reduce. If you wanted to check for if any of the filter conditions are true, you would change it to
data.filter(function(obj) {
return filter.reduce(function(a, f) {
return a || (obj[f.key] === f.value);
}, false);
});
You can do this way as well:
var filters = [{key: "pl", value: 3}, {key: "sh", value: 2}]
var data = [
{
title: "The Uncertainty of the Poet ",
pl: 2,
si: 2,
va: 3,
te: 0,
co: 0,
or: 4,
sh: 3,
po: 0,
li: 0,
ar: 5
},
{
title: "Direction",
pl: 3,
si: 3,
va: 1,
te: 3,
co: 0,
or: 3,
sh: 2,
po: 0,
li: 0,
ar: 5
}
]
var result = data.filter((item) => {
for(let i = 0; i < filters.length; ++i) {
let filter = filters[i];
if(item[filter.key] && item[filter.key] === filter.value) {
return true;
}
}
return false;
});
If you want it to match one or the other values, this will work:
match = [ {key: "pl", value: 3}, {key: "sh", value: 2} ]
var result = data.filter(function(d) {
return d.pl === match[0]['value'] || d.sh === match[1]['value']
})
I've changed the name of the array to match to avoid confusion.
You aren't going deep enough with your for in. It is looping over the array and not working with each object in the array
Can use Array#every() to make sure every object in filter array has match in the data object
// filter main data
var result = data.filter(function(dataObj){
// check if all proprties within filter array are a match
return filter.every(function(filterObj){
//compare value of property found in filterObject with value
return dataObj[filterObj.key] === filterObj.value
})
})
console.log(result)
<script>
var filter = [ {key: "pl", value: 2}, {key: "sh", value: 3} ]
var data = [{
title: "The Uncertainty of the Poet ",
pl: 2,
si: 2,
va: 3,
te: 0,
co: 0,
or: 4,
sh: 3,
po: 0,
li: 0,
ar: 5
},
{
title: "Direction",
pl: 4,
si: 3,
va: 1,
te: 3,
co: 0,
or: 3,
sh: 2,
po: 0,
li: 0,
ar: 5
}
]
</script>

Categories

Resources