calculate the percent instead the sum - javascript

Actually my function calculate the sum of all same keys in each object
const arr = [{id:1, "my color":1,"my fruit":4},{id:2,"my color":2,"my fruit":4}];
const res = arr.reduce((a, { id, ...rest }) => {
Object.entries(rest).forEach(([key, val]) => {
a[key] = (a[key] || 0) + val;
});
return a;
}, {});
result is >> [{"my color":3,"my fruit":8}
I'd like to get their percent (value/sum of values) and not instead their sum, like this
{ "my color": 27, "my fruit": 73 }

Try following
var obj = {"my color":3,"my fruit":8};
var total = Object.values(obj).reduce((a,c) => a+c, 0);
Object.keys(obj).forEach(k => obj[k] = Math.round(obj[k]*100/total));
console.log(obj);

Well just sum up all values first, then divide each entry by that:
// Sum up all properties with same key
const sum = { };
for(const entry of array) {
for(const [key, value] of Object.entries(entry)) {
sum[key] = (sum[key] || 0) + value;
}
}
// Map the array to an array of percentages
const percentage = array.map(entry => {
const result = {};
for(const [key, value] of Object.entries(entry)) {
result[key] = value / sum[key] * 100;
}
return result;
});

Related

How do I combine/group string values of the same key within an array of objects

If I have an array of objects like:
arr = [{"apple":"sour"}, {"pear":"sweet"}, {"apple":"red"}]
Since arr[0] and arr[2] have the same key, what can I do to combine them separated by a space to form something like:
[{"apple":"sour red"},{"pear":"sweet"}]
const arr = [{"apple":"sour"}, {"pear":"sweet"}, {"apple":"red"}]
// create object
const obj = {}
// iterate through the array
for (const item of arr) {
// get the key e.g. apple
const key = Object.keys(item)[0]
// get the value e.g. sour
const value = item[key]
if (!(key in obj)) {
// create an array for each key
obj[key] = []
}
// push value to the key
obj[key].push(value)
}
// map object to final array
const result = Object.entries(obj).map(([key, value]) => ({ [key]: value.join(' ') }))
console.log(result)
A solution to use reduce to do it
const arr = [{"apple":"sour"}, {"pear":"sweet"}, {"apple":"red"}]
let data = arr.reduce((acc,val) =>{
let key = Object.keys(val)[0]
let obj = acc.find(a => a[key])
if(obj){
obj[key] = obj[key] +" " + val[key]
}else{
acc.push(val)
}
return acc
},[])
console.log(data)

Count all values in object where X is the first key letter

I would like to count all values where a letter appears first and return the letter with atleast half of all values in my object so for example I assuming I have an object like this
const sample = { "A,B,C": 4, "B,C,A": 3, "C,B,A": 2, "A,C,B": 2 };
I would return A because if you count all the values where A appears first you would get 6 (4+2)
This is what I currently have:
for (let votes of Object.values(sample)) {
sum += votes
}
stretchWin = Math.round(sum / 2)
winner = Object.entries(sample)
.filter(([, val]) => val >= stretchWin)
.map(([keys]) => keys)
With this I am getting an empty array because I am not counting all the values assigned to A
Iterate over the whole sample first to get a sum of the values by the first letter first, then iterate over that new object to identify which values match the target of half the total.
const sample = {
"A,B,C": 4,
"B,C,A": 3,
"C,B,A": 2,
"A,C,B": 2
};
const sumByChar = {};
for (const [key, value] of Object.entries(sample)) {
const char = key[0];
sumByChar[char] = (sumByChar[char] ?? 0) + value;
}
let sum = 0;
for (let votes of Object.values(sample)) {
sum += votes
}
const targetSum = Math.round(sum / 2);
const winners = Object.entries(sumByChar)
.filter(([, val]) => val >= targetSum)
.map(([key]) => key);
console.log(winners);
I'm not completely sure what you mean what the outcome should be. If I understand correctly you want something like this??
const sample = { "A,B,C": 4, "B,C,A": 3, "C,B,A": 2, "A,C,B": 2 };
const totalSum = Object.values(sample).reduce(
(previousValue, currentValue) => previousValue + currentValue,
0
);
const stretchWin = Math.round(totalSum / 2);
const winner = Object.entries(sample)
.filter(([key, value]) => {
const isFirstLetterA = key.startsWith("A");
return isFirstLetterA || value >= stretchWin;
})
.map(([key, value]) => value)
.reduce((previousValue, currentValue) => previousValue + currentValue, 0);
console.log(winner);

How to calculate the average of all object properties without specifying them explicitly by name? [duplicate]

Suppose to have an array of two or more objects as:
const arr =[{PM1:10, PM10:20},{PM1:20, PM10:30, CO:27}, {NO2:30}]
How can I efficiently compute average values for each property in the objects comprising the array?
I don't know in advance the properties in each object and even if there are common properties.
I would expect a result:
{PM1:15, PM10:25, CO:27, NO2:30}
I suppose that I can use reduce but I can't figure it out how.
You can loop through the property names of an object using either for-in (which includes inherited properties) or an array from Object.keys (which doesn't). In both cases, only enumerable properties are included.
For instance:
const arr =[{PM1:10, PM10:20},{PM1:20, PM10:30, CO:27}, {NO2:30}];
const result = {};
const counts = new Map();
for (const element of arr) {
for (const key in element) {
if (Object.hasOwn(element, key)) {
// Count this property
counts.set(key, (counts.get(key) ?? 0) + 1);
// Add it to the sum
result[key] = (result[key] ?? 0) + element[key];
}
}
}
// Update with the averages
for (const [key, count] of counts) {
result[key] = result[key] / counts.get(key);
}
Live Example:
// Quick-and-dirty polyfill for older environments without `Object.hasOwn`:
if (!Object.hasOwn) {
Object.defineProperty(Object, "hasOwn", {
value: Function.prototype.call.bind(Object.prototype.hasOwnProperty),
writable: true,
configurable: true,
});
}
const arr =[{PM1:10, PM10:20},{PM1:20, PM10:30, CO:27}, {NO2:30}];
const result = {};
const counts = new Map();
for (const element of arr) {
for (const key in element) {
if (Object.hasOwn(element, key)) {
// Count this property
counts.set(key, (counts.get(key) ?? 0) + 1);
// Add it to the sum
result[key] = (result[key] ?? 0) + element[key];
}
}
}
// Update with the averages
for (const [key, count] of counts) {
result[key] = result[key] / counts.get(key);
}
console.log(result);
just 2 reduce...
const arr =
[ { PM1:10, PM10:20}
, { PM1:20, PM10:30, CO:27}
, { NO2:30 }
]
const average =
arr.reduce((a,c)=>
{
for(let key in c)
{
let line = a.find( x=>x.k === key )
if (!line) a.push( line = { k:key, sum:0, nb:0 } )
line.sum += c[key]
++line.nb
}
return a
},
[]).reduce((a,c)=>
{
a[c.k] = c.sum / c.nb
return a
},{})
console.log ( average )
.as-console-wrapper { max-height: 100% !important; top: 0; }

Create an object from a string array

I'm trying to create an object from a string array.
I've this string array :
let BaseArray = ['origin/develop', 'origin/master', 'toto/branch', 'tata/hello', 'tata/world'];
and I would like to have an object like that :
{
origin : ['develop', 'master'],
toto : ['branch'],
tata : ['hello', 'world']
}
So for the moment, I did this :
let Obj = {};
let RemoteObj = {};
for (let CurrentIndex = 0; CurrentIndex < BaseArray.length; CurrentIndex++) {
let Splits = BaseArray[CurrentIndex].split('/');
if (Splits[0] && Splits[1]) {
Obj[Splits[0]] = Splits[1].trim();
}
if (this.isObjectEmpty(RemoteObj)) {
RemoteObj = Obj;
} else {
RemoteObj = this.mergeObjects(RemoteObj, Obj);
}
console.log(RemoteObj);
}
And my utils functions are :
mergeObjects(...objs) {
let Result = {}, Obj;
for (let Ind = 0, IndLen = objs.length; Ind < IndLen; Ind++) {
Obj = objs[Ind];
for (let Prop in Obj) {
if (Obj.hasOwnProperty(Prop)) {
if (!Result.hasOwnProperty(Prop)) {
Result[Prop] = [];
}
Result[Prop].push(Obj[Prop]);
}
}
}
return Result;
}
isObjectEmpty(Obj) {
for (let Key in Obj) {
if (Obj.hasOwnProperty(Key)) {
return false;
}
return true;
}
}
I'm sure there is a better solution to do it but I can't do it.
So I'm open to any help !
Thanks by advance !
You can use Array.reduce() to create the object by splitting each string to the key and value, assigning an empty array to the key if it doesn't exist, and pushing the value to the array:
const BaseArray = ['origin/develop', 'origin/master', 'toto/branch', 'tata/hello', 'tata/world'];
const result = BaseArray.reduce((r, str) => {
const [key, value] = str.split('/');
if(!r[key]) r[key] = [];
r[key].push(value);
return r;
}, {});
console.log(result);
You can use Array.reduce() for this approach. On each iteration of reduce you can split your string by / and use the first element as a key on the new object and then put the second element on the array associated with that key:
let BaseArray = ['origin/develop', 'origin/master', 'toto/branch', 'tata/hello', 'tata/world'];
let res = BaseArray.reduce((acc, curr) =>
{
let [k, v] = curr.split("/");
(acc[k] = acc[k] || []).push(v);
return acc;
}, {});
console.log(res);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
You can use split and reduce
let BaseArray = ['origin/develop', 'origin/master', 'toto/branch', 'tata/hello', 'tata/world'];
let op = BaseArray.reduce((op, inp) => {
let [key, value] = inp.split('/')
op[key] = op[key] || []
op[key].push(value)
return op
},{})
console.log(op)
You can use the reduce method to build your object.
let baseArray = ['origin/develop', 'origin/master', 'toto/branch', 'tata/hello', 'tata/world'];
let baseobj = baseArray.reduce((acc, curr) => {
let items = curr.split('/');
let key = items[0];
let value = items[1];
if(acc[key] === undefined) {
acc[key] = [value]
} else {
acc[key] = [...acc[key], value];
}
return acc;
}, {});
console.log(baseobj);
You can use reduce & split the string which will give an array. Then use the element at index 0 of the array to create the object key. And push rest of the value to the array
let BaseArray = ['origin/develop', 'origin/kit/sub', 'origin/master', 'toto/branch', 'tata/hello', 'tata/world'];
let newArray = BaseArray.reduce(function(acc, curr) {
let splitCurr = curr.split('/');
if (!acc[splitCurr[0]]) {
acc[splitCurr[0]] = []
}
for (let i = 1; i < splitCurr.length; i++) {
acc[splitCurr[0]].push(splitCurr[i])
}
return acc;
}, {});
console.log(newArray)

Convert String Into Delimited Object Key

I am trying to convert a string into a delimited object key but I need some assistance on how to iterate over the length of the array and join accordingly.
SET('my.delimited.string.of.unknown.length')
const SET = key => (state, val) => {
if(key.indexOf('.') !== -1) {
let array = key.split(".")
for (var i = 0; i < array.length; i++) {
// what should I do here?
}
// desired output based on array length
// state[ array[0] ][ array[1] ] = val
// state.my.delimited.string.of.unknown.length = val
}
}
One of those very rare usecases for reduce:
const keys = key.split(".");
const prop = keys.pop();
keys.reduce((acc, key) => acc[key], state)[prop] = val;
For sure that could also be done with a for loop:
let array = key.split("."), acc = state;
for (var i = 0; i < array.length - 1; i++) {
acc = acc[ array[i] ];
}
acc[ array.pop() ] = val;
For setting a value, you could split the path and reduce the path by walking the given object. If no object exist, create a new property with the name. Later assign the value.
function setValue(object, path, value) {
var keys = path.split('.'),
last = keys.pop();
keys.reduce((o, k) => o[k] = o[k] || {}, object)[last] = value;
}
var test = {};
setValue(test, "first.deep.property", 1);
setValue(test, "and.another.deep.property", 20);
console.log(test);
You could also do this with a single Array.reduce:
const makeObject = (arr, val, obj={}) => {
arr.split('.').reduce((r,c,i,a) => r[c] = i == a.length-1 ? val : {}, obj)
return obj
}
console.log(makeObject("first.deep.property", 1))
console.log(makeObject("and.another.deep.property", 20))

Categories