add up all value from array of objects's key after parseFloat() - javascript

so I have an array of objects inside like this:
let ary = [
{
a : 'something',
b: '2',
c: 'something'
},
{
a : 'something',
b: '2',
c: 'something'
},
{
a : 'something',
b: '2',
c: 'something'
}
]
I need to add up all key b's value on each object so I first change them to number with parseFloat like this:
ary.forEach( item => {
item.b = parseFloat(item.b)
})
Next I use reduce() inside a .map function.
let total = ary.map((item, index) => {
return ary.reduce((a, b) => ({x: a.b + b.b}))
})
but I did not get what I want, it return an array of objects with both same total value.
array = [
{x : total},
{x : total}
]
How should I get just single total value? like
total = 2+2+2 and each 2 is from the b key in ary.

You can try with:
const total = ary.reduce((sum, item) => (sum + parseFloat(item.b)), 0);
With one loop you'll invoke parseFloat and summ all b properties.

You could chain some methods by separating the value of the objects, take numbers and add all values with reduce.
var array = [{ a: 'something', b: '2', c: 'something' }, { a: 'something', b: '2', c: 'something' }, { a: 'something', b: '2', c: 'something' }],
sum = array
.map(({ b }) => b)
.map(Number)
.reduce((a, b) => a + b);
console.log(sum);

Related

Compare two objects with specified keys in TS

I am trying to compare two objects but only with three keys instead of all keys. It looks like this:
Object.keys(StateA)
.filter((k) => [k == 'name', 'x', 'y'])
.every((k) => StateA[k] == StateB[k])
)
I am getting false results; what I am doing wrong?
There's no need to filter keys if you already have/know the ones to compare beforehand; use every just as you are:
const A = { a: 0, b: 1, c: 2, x: 3, y: 4, z: 5 };
const B = { a: 0, b: 2, c: 3, x: 3, y: 4, z: 6 };
const match = ['a', 'x', 'y'].every(key => A[key] === B[key]);
console.log(match);
Keep in mind a simple check like this may give you false positives - it depends on what you want. One case would be a key missing in one object but present in the other set to undefined. If that's the case, you may want to also check for the presence of the key:
const A = { a: 0, b: 1, c: undefined };
const B = { a: 0, b: 1 };
const keys = ['a', 'b', 'c'];
const match = keys.every(key => A[key] === B[key]);
console.log(match); // true
const stricterMatch = keys.every(key => (
key in A && key in B && A[key] === B[key]
));
console.log(stricterMatch); // false
export function hasSameProps (source: Record<string,unknown>, target: Record<string,unknown>) {
Object.keys(source).every(key => target.hasOwnProperty(key));
or
for (const key in ObjA) {
const current = ObjB[key];
if (!current) {
// does not exists
}
}

How to intersect and combine multiple object arrays using javascript

I'm trying to find the intersection between n >=2 object arrays which share the same key while also combining the object arrays. I'm looking for the most efficient way to do this. The max length of any of the arrays would be around ~2500 objects long.
An example of what I'm looking for :
object1 = [
{
key: 'key1',
x: 'x',
y: 'y',
z: 'z'
},
{
key: 'key2',
x: 'x',
y: 'y',
z: 'z'
}
]
object2 = [
{
key: 'key1',
a: 'a',
b: 'b'
},
{
key: 'key3',
a: 'a',
b: 'b'
}
]
object3 = [
{
key: 'key1',
c: 'c'
},
{
key: 'key4',
c: 'c'
}
]
with the desired output :
object = [
{
key: 'key1',
x: 'x',
y: 'y',
z: 'z',
a: 'a',
b: 'b',
c: 'c'
}
]
To combine two object arrays, I've used the following function :
let map = new Map(object1.map(o => [o['key'], o]));
return object2.reduce((acc, o) => {
let match = map.get(o['key']);
return match ? acc.concat({ ...o, ...match }) : acc;
}, []);
But I'm not sure how to apply this to more arrays in a way that's not resource and time heavy. Any tips would be appreciated. I'm also open for using helper functions like underscore or lodash.
The advantage (i hope) with this code is that it will preprocess all objects first to find intersecting keys before attempting to reduce and combine each one. In the first iteration fkeys flattens all objects together so we can do just one loop.
Separating those 2 processes should reduce overhead. My guess though is that there's a more elegant way to do this. I added in another intersecting key (key2) for demonstration in snippet
let objs = [object1, object2, object3],
fkeys = Object.keys(Object.fromEntries(Object.entries([...objs.flat()].map(o => o.key).reduce((b, a) => {
if (b.hasOwnProperty(a)) b[a] = b[a] + 1;
else b[a] = 1;
return b
}, {})).filter(k => k[1] === objs.length))),
intersections = Object.values([...objs.flat()].filter(o => fkeys.includes(o.key)).reduce((b, a) => {
if (b.hasOwnProperty(a.key)) b[a.key] = { ...b[a.key], ...a};
else b[a.key] = { ...a};
return b}, {}))
object1 = [{
key: 'key1',
x: 'x',
y: 'y',
z: 'z'
},
{
key: 'key2',
g: 'g',
h: 'h',
j: 'j'
}
]
object2 = [{
key: 'key1',
a: 'a',
b: 'b'
},
{
key: 'key2',
y: 'y',
z: 'z'
},
{
key: 'key3',
a: 'a',
b: 'b'
}
]
object3 = [{
key: 'key1',
c: 'c'
},
{
key: 'key2',
r: 'r'
},
{
key: 'key4',
c: 'c'
}
]
let objs = [object1, object2, object3],
fkeys = Object.keys(Object.fromEntries(Object.entries([...objs.flat()].map(o => o.key).reduce((b, a) => {
if (b.hasOwnProperty(a)) b[a] = b[a] + 1;
else b[a] = 1;
return b
}, {})).filter(k => k[1] === objs.length))),
intersections = Object.values([...objs.flat()].filter(o => fkeys.includes(o.key)).reduce((b, a) => {
if (b.hasOwnProperty(a.key)) b[a.key] = { ...b[a.key],
...a
};
else b[a.key] = { ...a
};
return b;
}, {}))
console.log(fkeys)
console.log(intersections)

Get the frequency of elements in an array and store them in key value pairs

I have an array of elements and I want to get the frequency of the elements in an array, which is fine. How do I convert the object to store these elements and frequencies in a format to have property names or keys
var array = ['a','a','a','b','b','c','d','d','d','d',]
obj = [{ element: 'a', frequency: 3},
{ element: 'b', frequency: 2},
{ element: 'c', frequency: 1},
{ element: 'd', frequency: 4}]
Right now I have a solution that just returns:
obj = { a : 3, b : 2, c : 1, d : 4 }
You can convert it using Object.entries like below.
const obj = {
a: 3,
b: 2,
c: 1,
d: 4
};
const target = Object.entries(obj).map(v => ({
element: v[0],
frequency: v[1]
}));
console.log(target);
You can use Array#map on Object.entries with destructuring.
const obj = { a : 3, b : 2, c : 1, d : 4 };
const res = Object.entries(obj).map(([element,frequency])=>({element,frequency}));
console.log(res);
Using a map for quick & easy access while you compute the frequencies is a good idea but what stops you from creating the desired objects directly?
e.g. instead of
{ a: 3
, b: 2
}
Why not?
{ a: {element: 'a', frequency: 3}
, b: {element: 'b', frequency: 2}
}
You then simply need to Object.values(obj) to get what you want.
const freq =
xs =>
Object.values
( xs.reduce
( (acc, x) =>
( acc[x] = acc[x] || {element: x, frequency: 0}
, acc[x].frequency += 1
, acc
)
, {}
)
);
console.log(freq(['a','a','a','b','b','c','d','d','d','d']));

Cleaner way to filter properties from object

I created a function to remove the properties I tell him to
function trimProperties(data, properties) {
return data.map(o => {
Object.keys(o).forEach(k => {
if (properties.includes(k)) {
delete o[k];
}
});
return o;
});
}
My use case is usually like this
let array = [
{
a: 'A',
b: 'B',
c: 'C'
},
{
a: 'A2',
b: 'B2',
c: 'C2'
}
]
// Remove every property 'b' or 'c' from the objects inside the array
trimProperties(array, ['b','c']);
My question is simple, how can I make this function faster, because my array sometimes can get pretty big since it's the result set from a database access
delete cause indexes recalculation all the time, creating new array would be faster
let array = [
{
a: 'A',
b: 'B',
c: 'C'
},
{
a: 'A2',
b: 'B2',
c: 'C2'
}
]
function trimProperties(data, properties) {
let i = 0;
const result = []
while (i < data.length) {
var o = {};
Object.keys(data[i]).forEach(k => {
if (!properties.includes(k)) {
o[k] = data[i][k];
}
})
i++;
if (Object.keys(o).length) {
result.push(o);
}
}
return result;
}
// Remove every property 'b' or 'c' from the objects inside the array
console.log(trimProperties(array, ['b','c']));
A one liner:
array.map(o => Object.fromEntries(Object.entries(o).filter(([k,v]) => !['b','c'].includes(k))))
Demo:
const array = [
{
a: 'A',
b: 'B',
c: 'C'
},
{
a: 'A2',
b: 'B2',
c: 'C2'
}
];
const excluded = ['b','c'];
const filtered = array.map(o => Object.fromEntries(Object.entries(o).filter(([k,v]) => !excluded.includes(k))));
console.log(filtered)

Using reduce to add values of properties of a collection objects in JavaScript

Pretty straight forward:
var bar = [
{ a: 10, b: 20 }, { a: 10, b: 20 }
];
var reduce = bar.reduce((acc, item) => {
acc['a'] = item.a++;
acc['b'] = item.b++
return acc;
}, {});
console.log(reduce);
{a: 10, b: 20}
I'd like reduce assigned the reference: {a:20, b: 40}
Here is a general solution that will work even if your object inside your array contains different properties.
var bar = [
{ a: 10, b: 20 }, { a: 10, b: 20 }
];
var reduce = bar.reduce((acc, item) => {
for (let [key, value] of Object.entries(item)){
if( acc.hasOwnProperty(key)) {
acc[key] += value
}
else {
acc = {...acc, [key]: value }
}
}
return acc;
}, {});
console.log(reduce);
Rather than assigning the accumulator's property the item's property incremented by one, you should add to the existing accumulator's property value. You also shouldn't pass an initial object to the reduce given this implementation (or, if you do, you'll need to define the a and b properties).
Since you're using reduce, I think you should also consider using const instead of var - const is less bug-prone and easier to read:
const bar = [
{ a: 10, b: 20 }, { a: 10, b: 20 }
];
const reduced = bar.reduce((acc, item) => {
acc.a += item.a;
acc.b += item.b;
return acc;
});
console.log(reduced);
You could return a new object with added values.
var bar = [{ a: 10, b: 20 }, { a: 10, b: 20 }],
reduce = bar.reduce((a, b) => ({ a: a.a + b.a, b: a.b + b.b }));
console.log(reduce);
Or with a complete dynamic approach for all properties.
const add = (a, b) =>
Object.assign({}, a, ...Object.entries(b).map(([k, v]) => ({ [k]: a[k] + v })));
var bar = [{ a: 10, b: 20 }, { a: 10, b: 20 }],
reduce = bar.reduce(add);
console.log(reduce);

Categories