Sorry, in advance if the title is unclear, but it's hard to describe it in a words.
What I have:
const obj = {
a: 5,
b: 3,
c: 0,
d: 9
}
What I want to have:
const arr = [[a, 5] ,[b, 3]]
Basically, I try to write a function that return me array of entries, but it has too meet requirements:
don't want objects when values is equal to 0
sum of values must be less than 10
First point is easy for me and I can do it by
Object.entries(obj).filter(([k, v])=> v !== 0)
but I can't handle with the second one.
May I use reduce here?
You can use a closure and an IIFE to store the sum
Object.entries(obj).filter((() => {
let sum = 0;
return ([k, v]) => { sum += v; return v !== 0 && sum < 10; };
})());
Examples:
function convert(obj) {
return Object.entries(obj).filter((() => {
let sum = 0;
return ([k, v]) => { sum += v; return v !== 0 && sum < 10; };
})());
}
const obj = { a: 5, b: 3, c: 0, d: 9 };
const arr = convert(obj);
console.log(arr);
const obj2 = { a: 0, b: 0, c: 8, d: 0, e: 1, f: 5 };
const arr2 = convert(obj2);
console.log(arr2);
const obj3 = { a: 12 };
const arr3 = convert(obj3);
console.log(arr3);
#jabaa's answer is great and you should accept it.
Just to confirm your intuition, you could have used reduce, but it would get rather complicated:
const obj = {
a: 5,
b: 3,
c: 0,
d: 9
}
const result = Object.entries(obj).reduce(
(o, newPair) => {
o.sum += newPair[1];
newPair[1] !== 0 && o.sum < 10 && o.pairs.push(newPair);
return o;
},
{
sum: 0,
pairs: []
}
).pairs;
console.log(result)
Related
const ob = {
a: 1,
b: {
c: 3,
d: 6,
e: {
f: {
g: 3,
h: {
i: 5,
j: {
k: 7
}
}
}
}
}
};
Any methods to solve this code?
I have no idea how to solve this code.
For abovementioned input I would expect a result of 1 + 3 + 6 + 3 + 5 + 7 = 25. So what I want to return from a function sumObject(ob) is: 25
You can try reduce with recursion
The condition for the sum is
If the current value is a number, sum it with result
If the current value is not a number (in your case, it's an object), call the function sumObject recursively with current result
const ob = {
a: 1,
b: {
c: 3,
d: 6,
e: {
f: {
g: 3,
h: {
i: 5,
j: {
k: 7
}
}
}
}
}
};
function sumObject(data, result = 0) {
return Object.values(data).reduce((sum, value) => typeof value === 'number' ? sum + value : sumObject(value, sum), result)
}
console.log(sumObject(ob))
If you don't understand some of the other answers, this is an easier solution to understand:
function sumObject(obj){
let result = 0;
for(let i of Object.values(obj)){ //we iterate through all values in obj
if(typeof i == "number"){ //if the current value of i is a number
result+=i; //then add that to the result
} else { //otherwise, it will be an object
result+=sumObject(i); //so we call the function on itself to iterate over this new object
}
}
return result; //finally, we return the total
}
console.log(sumObject(ob));
You can do this to extract all values into an array of numbers and then sum that array:
const getObjectValues = (obj) => (obj && typeof obj === 'object')
? Object.values(obj).map(getObjectValues).flat()
: [obj]
let nums = getObjectValues(ob)
let sum = nums.reduce((a, b) => a + b, 0)
You can recursively sum the value of each object using array#reduce and Object.values()
const ob = { a: 1, b: { c: 3, d: 6, e: { f: { g: 3, h: { i: 5, j: { k: 7 } } } } } },
getSum = o =>
Object.values(o).reduce((s, v) => {
s += typeof v === 'object' ? getSum(v): v;
return s;
}, 0);
console.log(getSum(ob));
Try recursion. This will support any amount of nested object at any level of nesting.
const sumAllNumbers = (object, total = 0) => {
const nextValues = [];
for (const value of Object.values(object)) {
if (typeof value === 'number') total += value;
if (typeof value === 'object') nextValues.push(Object.values(value));
}
if (!nextValues.length) return total;
return sumAllNumbers(nextValues.flat(), total);
};
// adds up to 25
const testCase1 = {
a: 1,
b: {
c: 3,
d: 6,
e: {
f: {
g: 3,
h: {
i: 5,
j: {
k: 7,
},
},
},
},
},
};
// adds up to 30
const testCase2 = {
a: 1,
b: 2,
c: {
a: 1,
b: 2,
c: 3,
d: {
a: 5,
b: {
c: {
d: {
e: 1,
},
},
},
},
},
d: {
g: {
f: {
c: 10,
},
},
},
e: {
f: {
a: 1,
g: {
a: 4,
},
},
},
};
// Your original test case
console.log(sumAllNumbers(testCase1));
// My much more demanding test case
console.log(sumAllNumbers(testCase2));
You could get the value of the objects and check if the value is an object, then take the result of the nested objects or call the handed over sum function for accumulator and actual value.
This approach works with a function which takes
an object
an accumulator function
a start value
This function works as well for getting all values with different accumulator function and an array as startValue.
const
reduce = (object, fn, startValue) => Object
.values(object)
.reduce(
(r, v) => v && typeof v === 'object' ? reduce(v, fn, r) : fn(r, v),
startValue
),
data = { a: 1, b: { c: 3, d: 6, e: { f: { g: 3, h: { i: 5, j: { k: 7 } } } } } },
total = reduce(data, (a, b) => a + b, 0);
console.log(total);
const ob = {
a: 1,
b: {
c: 3,
d: 6,
e: {
f: {
g: 3,
h: {
i: 5,
j: {
k: 7
}
}
}
}
}
};
const sum = data =>
Object
.keys(data)
.reduce((a,b) => a + (typeof(s = data[b]) == "number" ? s : sum(s)), 0);
console.log(sum(ob))
I have two arrays and each of them has objects. How best can I simplify adding two objects into one but in a new list. e.g
a = [{a:1, b:2, c:3}, {d:1, e:4, f:2}]
b = [{m:1, n:2, o:4}, {r:1,s:3,u:5}, {k:1,j:4,f:8}]
z = [{a:1, b:2, c:3, m:1, n:2, o:4}, {d:1, e:4, f:2, r:1,s:3,u:5}, {k:1,j:4,f:8}]
Suppose you have list a and b, I want to add the objects of each position together in list z.
You could merge the two object in this way:
let a = [{a:1, b:2, c:3}, {d:1, e:4, f:2}]
let b = [{m:1, n:2, o:4}, {r:1,s:3,u:5}, {k:1,j:4,f:8}]
let z = [];
b.forEach((x, i) => {
let merged = {...x, ...a[i]};
z.push(merged)
})
console.log(z);
I'd go over the maximum length of a and b and use Object.assign to copy the values. Assuming you want a generic solution to any two arrays, where either can be longer than the other, note that you need to check the lengths as you go:
z = [];
for (let i = 0; i < Math.max(a.length, b.length); ++i) {
const result = i < a.length ? a[i] : {};
Object.assign(result, i < b.length ? b[i] : {});
z.push(result);
}
Try this :
const a = [{a:1, b:2, c:3}, {d:1, e:4, f:2}];
const b = [{m:1, n:2, o:4}, {r:1,s:3,u:5}, {k:1,j:4,f:8}];
let c = [];
if(a.length > b.length){
c = a.map((e,i) => {
return {
...e,
...b[i]
}
});
}else{
c = b.map((e,i) => {
return {
...e,
...a[i]
}
});
}
console.log(c);
You could check first the length of both arrays and then merge them.
const a = [{ a: 1, b: 2, c: 3 }, { d: 1, e: 4, f: 2 }]
const b = [{ m: 1, n: 2, o: 4 }, { r: 1, s: 3, u: 5 }, { k: 1, j: 4, f: 8 }]
const mergeArrays = (arr1, arr2) => arr1.map((x, i) => ({ ...x, ...arr2[i] }))
const z = a.length > b.length ? mergeArrays(a, b) : mergeArrays(b, a);
console.log(z);
Logic
Create a new array with length of maximum of both array. Using that array indices return data from array a and b
const a = [{ a: 1, b: 2, c: 3 }, { d: 1, e: 4, f: 2 }]
const b = [{ m: 1, n: 2, o: 4 }, { r: 1, s: 3, u: 5 }, { k: 1, j: 4, f: 8 }];
const z = Array.from({ length: Math.max(a.length, b.length) }, (_, index) => ({ ...a[index] , ...b[index] }));
console.log(z);
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
}
}
I have to calculate a sum of certain object values ( not all )
I have this object :
let object = {a: 1, b: 4, c: 2, d: 3, e: 10}
I need to sum just the a, c, d, e values.
Actually I use this method which sums all the values and gives me 20, but I need to have 16.
Object.keys(object).reduce((sum, key) => sum + parseFloat(object[key] || 0), 0)
How can I do this sum ?
Your sum function is good as it is, you just need to apply a filter
Object.keys(object)
.filter(key => key !== 'b')
.reduce((sum, key) => sum + parseFloat(object[key] || 0), 0)
Or, if you want a whitelist
const validKeys = {
a: true,
b: false, // optional
c: true,
d: true,
e: true
}
Object.keys(object)
.filter(key => validKeys[key])
.reduce((sum, key) => sum + parseFloat(object[key] || 0), 0)
To follow what you originally did, You should have an array of the keys and check to see if it is included before you add it.
const myObject = {a: 1, b: 4, c: 2, d: 3, e: 10}
const keys = ['a', 'c','d', 'e']
const entries = Object.entries(myObject)
const result = entries.reduce( (total, [key, value]) => (keys.includes(key) ? value : 0) + total, 0)
console.log(result)
smarter way is to loop over the keys
const myObject = {a: 1, b: 4, c: 2, d: 3, e: 10}
const keys = ['a', 'c','d', 'e']
const result = keys.reduce( (total, key) => (myObject[key] || 0) + total, 0)
console.log(result)
I'll add my two cents to the thread for...in is awesome too xD
let object = {a: 1, b: 4, c: 2, d: 3, e: 10}
let sum = 0;
const keys = ['a', 'c', 'd', 'e'];
for(let key in object) {
if(keys.includes(key)) //or key === 'a' || key === 'c' ..
sum += object[key];
}
console.log(sum);
You could take the wanted keys directly.
let object = {a: 1, b: 4, c: 2, d: 3, e: 10},
keys = ['a', 'c', 'd', 'e'],
result = keys.reduce((sum, key) => sum + (object[key] || 0), 0);
console.log(result);
You could either declare the keys you want to sum (whitelist) or those you wish to omit (blacklist). I've used the latter approach here:
let object = {a: 1, b: 4, c: 2, d: 3, e: 10},
ignore = ['b'],
sum = Object.keys(object)
.filter(key => !ignore.includes(key))
.reduce((total, key) => total += object[key], 0);
console.log(sum); //16
Fiddle
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);