Adding up the values of an array of objects javascript - javascript

I have an array of objects like this : const array=[{a:1, b:1} , {a:2, b:3} ,{a:1, b:1}]
i want an array like results = [{a:4 , b:5}] which is the sum of all values from the array of objects according to the key .
I tried something like this but sometimes it skipping the 1st object in the array :
array.reduce((acc, n) => {
for (var prop in n) {
if (acc.hasOwnProperty(prop)) acc[prop] += n[prop];
else acc[prop] = 0;
}
return acc;
}, {})

You need to initialize acc before assigning, so small modification below will work
const array=[{a:1, b:1} , {a:2, b:3} ,{a:1, b:1}]
const res = array.reduce((acc, n) => {
for (var prop in n) {
acc[prop] = acc[prop] || 0; // Need to initialize before assigning
if (n.hasOwnProperty(prop)) {
acc[prop] += n[prop];
}
}
return acc;
}, {})
console.log(res);

This will work
const res = [{a:1, b:1, c: 1} , {a:2, b:3, c:3} ,{a:1, b:1, c: 3}].reduce((a,v,i) => {
for(let key in v) {
a[key] = a[key] ? a[key] + v[key] : v[key];
}
return a
},{})
console.log(res)

You can use this code and you won't have to specify the object properties manually, it will create a new property if it doesn't exist, or add to the existing property if it does exist.
var myarr = [{a: 2, b: 3}, {a:3, b:2}];
var newobj = {};
for (var i=0; i <= myarr.length; i += 1)
for (var p in myarr[i]) newobj[p] = (p in newobj) ?
newobj[p] + myarr[i][p] : myarr[i][p]
console.log(newobj);

use forEach and Object.entries will simplify.
const array = [
{ a: 1, b: 1 },
{ a: 2, b: 3 },
{ a: 1, b: 1 },
];
const acc = (arr) => {
const res = {};
arr.forEach((obj) =>
Object.entries(obj).forEach(
([key, value]) => (res[key] = key in res ? res[key] + value : value)
)
);
return [res];
};
console.log(acc(array));

Related

Js obj with key name defined by Object.keys

var c = {
'aa-bb': [{ a: 1, v: 2}],
'cc-xz': [{ c: 2}]
}
console.log(Object.keys(c))
I need to create an object, whose keys (the name) must be from Object.keys.
For each key name an object of type array must be defined as below.
Can you give me a hand?
result:
const res = {
'aa-bb': Array(number).fill(0),
'cc-xz': Array(number).fill(0)
};
var c = {
'aa-bb': [{
a: 1,
v: 2
}],
'cc-xz': [{
c: 2
}]
}
const keys = Object.keys(c);
let res = {},
number = 5;
keys.forEach(key => res[key] = Array(number).fill(0));
console.log(res);
Map the keys, and create pairs of [key, array], and convert back to an object using Object.fromEntries():
const fn = (obj, arrLengh) =>
Object.fromEntries(
Object.keys(obj)
.map(key => [key, Array(arrLengh).fill(0)])
);
const c = {"aa-bb":[{"a":1,"v":2}],"cc-xz":[{"c":2}]};
const result = fn(c, 5);
console.log(result);

How to use Array.protoype.map() on array of objects to filter out some specific keys based on it's values?

I have the following array of objects, in which some specific keys have a value which is either a string or an array. I want to get the keys with string values as it is and remove "NA" from keys with array values.
I am trying to achieve the same by doing .map method on the array, check the type of the value of each key in the data object, if an array then use .filter to remove the "NA" values.
var dataArr = [
{
a: 'foo',
b: [1, 2, "NA", "NA", 3],
c: ["NA", 6]
},
{
a: 'bar',
b: ["NA", "NA", "NA"],
c: []
}
];
dataArr.map(dataObj => {
for (let key in dataObj) {
if (key !== 'a')
dataObj[key] = dataObj[key].filter(val => { if(val != "NA") return val})
}
return dataObj;
});
The above block of code works as expected but I want a better and future-proof solution. Moreover, this looks bad too.
If you just want to update the original array, you could loop through the array using forEach. Then loop through each object's keys using for...in and check if it is an array using Array.isArray(). Update the property after filtering out the NA value
const dataArr = [{a:'foo',b:[1,2,"NA","NA",3],c:["NA",6]},{a:'bar',b:["NA","NA","NA"],c:[]}];
dataArr.forEach(o => {
for (const key in o) {
if (Array.isArray(o[key]))
o[key] = o[key].filter(s => s !== "NA")
}
})
console.log(dataArr)
If you want to get a new array without mutating the original objects, you can use map like this:
const dataArr = [{a:'foo',b:[1,2,"NA","NA",3],c:["NA",6]},{a:'bar',b:["NA","NA","NA"],c:[]}];
const newArray = dataArr.map(o => {
const newObj = {};
for (const key in o) {
if (Array.isArray(o[key]))
newObj[key] = o[key].filter(s => s !== "NA")
else
newObj[key] = o[key]
}
return newObj;
})
console.log(newArray)
You can do that using nested map() and filter()
First of all use map() on the main array.
Then get the entries of each object using Object.entries()
Then use map() on the entries of each object.
Return the value as it is if the Array.isArray is false otherwise return the filtered value of array.
Finally use Object.fromEntries() to make an object.
var dataArr = [
{
a: 'foo',
b: [1, 2, "NA", "NA", 3],
c: ["NA", 6]
},
{
a: 'bar',
b: ["NA", "NA", "NA"],
c: []
}
];
const res = dataArr.map(x =>
Object.fromEntries(
Object.entries(x)
.map(([k,v]) =>
[k,Array.isArray(v) ? v.filter(b => b !== "NA") : v])
)
)
console.log(res)
Use for...of on the object's entries. For each entry check if it's an array. If it's an array filter, and then assign to the new object. If not, assign without filtering. This will not mutate the original array.
const dataArr = [{"a":"foo","b":[1,2,"NA","NA",3],"c":["NA",6]},{"a":"bar","b":["NA","NA","NA"],"c":[]}]
const result = dataArr.map(dataObj => {
const filterObject = {};
for (const [key, val] of Object.entries(dataObj)) {
filterObject[key] = Array.isArray(val) ?
dataObj[key].filter(val => val != 'NA')
:
val;
}
return filterObject;
});
console.log(result);
const dataArr = [{
a: 'foo',
b: [1, 2, "NA", "NA", 3],
c: ["NA", 6]
},
{
a: 'bar',
b: ["NA", "NA", "NA"],
c: []
}
];
const res = dataArr.map((obj) => {
for(let i in obj){
if(Array.isArray(obj[i])){
obj[i] = obj[i].filter(el=>el!=="NA")
}
}
return obj;
});
console.log('#>res', res)
I guess this will be a better code refactor,pls provide with the desired output also:
dataArr.forEach(object=>{
for (let value in object){
let isArr = Object.prototype.toString.call(data) == '[object Array]';
isArr? object[value] = object[value].filter(val => {return val != "NA"}):null}
})

How can i get an object from an array of objects

At the entrance I have such an array with objects.
Function that converts an incoming array of objects into an object.
Using the function, I need to bring it to this form.
var array = [
{ k1:v1 },
{ k2:v2 },
{ k3:v3 }
];
function arrayToObject(array) { return object }
var object = {
v1: k1,
v2: k2,
v3: k3,
}
You could taske Object.assign and spread the reversed objects.
var array = [ { k1: 'v1' }, { k2: 'v2' }, { k3: 'v3' }],
object = Object.assign(...array.map(o => Object
.entries(o)
.reduce((r, [k, v]) => Object.assign(r, { [v] : k }), {})
));
console.log(object);
Use forEach loop
var array = [
{ k1:'v1' },
{ k2:'v2' },
{ k3:'v3' }
]
function a()
{
var obj={};
array.forEach((e)=>obj[e[Object.keys(e)[0]]]=Object.keys(e)[0])
console.log(obj)
}
a();
You can use Object.entries() and .reduce() methods to get the desired output:
const array = [
{ k1:'v1' },
{ k2:'v2' },
{ k3:'v3' }
];
const obj = Object.entries(
array.reduce((r, c) => Object.assign(r, c), {})
).reduce((r, [k, v]) => (r[v] = k, r), {});
console.log(obj);
Array.reduce and use Object.keys over each array element.
var array = [
{ k1: 'v1' },
{ k2: 'v2' },
{ k3: 'v3' }
]
var obj = array.reduce((obj, item) => {
Object.keys(item).forEach(key => obj[item[key]] = key)
return obj
}, {})
console.log(obj)
And another one:
const result = {};
for(const [[key, value]] of array.map(Object.entries))
result[value] = key;
I am not sure why the other answers go through hoops to make this as clever as possible.
I find this more readable. I am not using reduce because I find the word misleading. A simple forEach makes more sense to me
const array = [
{ k1:'v1' },
{ k2:'v2' },
{ k3:'v3' }
];
let newObj={};
array.forEach((obj) => {
let key = Object.keys(obj)[0];
newObj[obj[key]]=key;
})
console.log(newObj)
your answer..
var array = [
{ k1: v1 },
{ k2: v2 },
{ k3: v3 }
];
function arrayToObject(array) {
obj = {};
for (i = 0; i < array.length; i++) {
o = array[i];
key = Object.keys(o)[0];
obj.key = o.key;
}
return obj;
}
console.log(arrayToObject(array))

Swap key with value in object

I have an extremely large JSON object structured like this:
{A : 1, B : 2, C : 3, D : 4}
I need a function that can swap the values with keys in my object and I don't know how to do it. I would need an output like this:
{1 : A, 2 : B, 3 : C, 4 : D}
Is there any way that I can do this would manually created a new object where everything is swapped?
Thanks
function swap(json){
var ret = {};
for(var key in json){
ret[json[key]] = key;
}
return ret;
}
Example here FIDDLE don't forget to turn on your console to see the results.
ES6 versions:
static objectFlip(obj) {
const ret = {};
Object.keys(obj).forEach(key => {
ret[obj[key]] = key;
});
return ret;
}
Or using Array.reduce() & Object.keys()
static objectFlip(obj) {
return Object.keys(obj).reduce((ret, key) => {
ret[obj[key]] = key;
return ret;
}, {});
}
Or using Array.reduce() & Object.entries()
static objectFlip(obj) {
return Object.entries(obj).reduce((ret, entry) => {
const [ key, value ] = entry;
ret[ value ] = key;
return ret;
}, {});
}
Now that we have Object.fromEntries:
const f = obj => Object.fromEntries(Object.entries(obj).map(a => a.reverse()))
console.log(
f({A : 'a', B : 'b', C : 'c'})
) // => {a : 'A', b : 'B', c : 'C'}
or:
const f = obj => Object.fromEntries(Object.entries(obj).map(([k, v]) => [v, k]))
console.log(
f({A : 'a', B : 'b', C : 'c'})
) // => {a : 'A', b : 'B', c : 'C'}
(Updated to remove superfluous parentheses - thanks #devin-g-rhode)
you can use lodash function _.invert it also can use multivlaue
var object = { 'a': 1, 'b': 2, 'c': 1 };
_.invert(object);
// => { '1': 'c', '2': 'b' }
// with `multiValue`
_.invert(object, true);
// => { '1': ['a', 'c'], '2': ['b'] }
Using ES6:
const obj = { a: "aaa", b: "bbb", c: "ccc", d: "ddd" };
Object.assign({}, ...Object.entries(obj).map(([a,b]) => ({ [b]: a })))
Get the keys of the object, and then use the Array's reduce function to go through each key and set the value as the key, and the key as the value.
const data = {
A: 1,
B: 2,
C: 3,
D: 4
}
const newData = Object.keys(data).reduce(function(obj, key) {
obj[data[key]] = key;
return obj;
}, {});
console.log(newData);
In ES6/ES2015 you can combine use of Object.keys and reduce with the new Object.assign function, an arrow function, and a computed property name for a pretty straightforward single statement solution.
const foo = { a: 1, b: 2, c: 3 };
const bar = Object.keys(foo)
.reduce((obj, key) => Object.assign({}, obj, { [foo[key]]: key }), {});
If you're transpiling using the object spread operator (stage 3 as of writing this) that will simplify things a bit further.
const foo = { a: 1, b: 2, c: 3 };
const bar = Object.keys(foo)
.reduce((obj, key) => ({ ...obj, [foo[key]]: key }), {});
Finally, if you have Object.entries available (stage 4 as of writing), you can clean up the logic a touch more (IMO).
const foo = { a: 1, b: 2, c: 3 };
const bar = Object.entries(foo)
.reduce((obj, [key, value]) => ({ ...obj, [value]: key }), {});
2021's answer
The concise way by using ES6 syntax like this.
const obj = {A : 1, B : 2, C : 3, D : 4}
console.log(
Object.entries(obj).reduce((acc, [key, value]) => (acc[value] = key, acc), {})
);
Explain:
(acc[value] = key, acc)
Using Comma operator (,) syntax.
The comma operator (,) evaluates each of its operands (from left to
right) and returns the value of the last operand.
As a complement of #joslarson and #jPO answers:
Without ES6 needed, you can use Object.keys Array.reduce and the Comma Operator:
Object.keys(foo).reduce((obj, key) => (obj[foo[key]] = key, obj), {});
Some may find it ugly, but it's "kinda" quicker as the reduce doesn't spread all the properties of the obj on each loop.
Using Ramda:
const swapKeysWithValues =
R.pipe(
R.keys,
R.reduce((obj, k) => R.assoc(source[k], k, obj), {})
);
const result = swapKeysWithValues(source);
Try
let swap = (o,r={})=> Object.keys(o).map(k=> r[o[k]]=k) && r;
let obj = {A : 1, B : 2, C : 3, D : 4};
let swap = (o,r={})=> Object.keys(o).map(k=> r[o[k]]=k) && r;
console.log(swap(obj));
With pure Ramda in a pure and point-free style:
const swapKeysAndValues = R.pipe(
R.toPairs,
R.map(R.reverse),
R.fromPairs,
);
Or, with a little more convoluted ES6 version, still pure functional:
const swapKeysAndValues2 = obj => Object
.entries(obj)
.reduce((newObj, [key, value]) => ({...newObj, [value]: key}), {})
Shortest one I came up with using ES6..
const original = {
first: 1,
second: 2,
third: 3,
fourth: 4,
};
const modified = Object
.entries(original)
.reduce((all, [key, value]) => ({ ...all, [value]: key }), {});
console.log('modified result:', modified);
var data = {A : 1, B : 2, C : 3, D : 4}
var newData = {};
Object.keys(data).forEach(function(key){newData[data[key]]=key});
console.log(newData);
Here is a pure functional implementation of flipping keys and values in ES6:
TypeScript
const flipKeyValues = (originalObj: {[key: string]: string}): {[key: string]: string} => {
if(typeof originalObj === "object" && originalObj !== null ) {
return Object
.entries(originalObj)
.reduce((
acc: {[key: string]: string},
[key, value]: [string, string],
) => {
acc[value] = key
return acc;
}, {})
} else {
return {};
}
}
JavaScript
const flipKeyValues = (originalObj) => {
if(typeof originalObj === "object" && originalObj !== null ) {
return Object
.entries(originalObj)
.reduce((acc, [key, value]) => {
acc[value] = key
return acc;
}, {})
} else {
return {};
}
}
const obj = {foo: 'bar'}
console.log("ORIGINAL: ", obj)
console.log("FLIPPED: ", flipKeyValues(obj))
function swapKV(obj) {
const entrySet = Object.entries(obj);
const reversed = entrySet.map(([k, v])=>[v, k]);
const result = Object.fromEntries(reversed);
return result;
}
This can make your object, {A : 1, B : 2, C : 3, D : 4}, array-like, so you can have
const o = {A : 1, B : 2, C : 3, D : 4}
const arrayLike = swapKV(o);
arrayLike.length = 5;
const array = Array.from(arrayLike);
array.shift(); // undefined
array; // ["A", "B", "C", "D"]
Here is an option that will swap keys with values but not lose duplicates, if your object is : { a: 1, b: 2, c: 2}, it will always return an array in the output :
function swapMap(map) {
const invertedMap = {};
for (const key in map) {
const value = map[key];
invertedMap[value] = invertedMap[value] || [];
invertedMap[value].push(key);
}
return invertedMap;
}
swapMap({a: "1", b: "2", c: "2"})
// Returns => {"1": ["a"], "2":["b", "c"]}
A simple TypeScript variant:
const reverseMap = (map: { [key: string]: string }) => {
return Object.keys(map).reduce((prev, key) => {
const value = map[key];
return { ...prev, [value]: [...(prev.value || []), key] };
}, {} as { [key: string]: [string] })
}
Usage:
const map = { "a":"1", "b":"2", "c":"2" };
const reversedMap = reverseMap(map);
console.log(reversedMap);
Prints:
{ "1":["a"], "2":["b", "c"] }
Rewriting answer of #Vaidd4, but using Object.assign (instead of comma operator):
/**
* Swap object keys and values
* #param {Object<*>} obj
* #returns {Object<string>}
*/
function swapObject(obj) {
return Object.keys(obj).reduce((r, key) => (Object.assign(r, {
[obj[key]]: key,
})), {});
}
Or, shorter:
Object.keys(obj).reduce((r, key) => (Object.assign(r, {[obj[key]]: key})), {});
function myFunction(obj) {
return Object.keys(obj).reduce((acc, cur) => {
return { ...acc, [obj[cur]]: cur };
}, {});
}
This is the solution that I'm using:
function objSwap(obj, tl = false) {
return Object.entries(obj).reduce((a, [k, v]) => (a[v = tl ? v.toLowerCase() : v] = k = tl ? k.toLowerCase() : k, a), {});
}
As a bonus: if you need to swap then check some values I added the possibility to lowercase keys and values. Simply you've to set tl = true, else if you don't need it ...
function objSwap(obj) {
return Object.entries(obj).reduce((a, [k, v]) => (a[v] = k, a), {});
}
Using a for...of loop:
let obj = {A : 1, B : 2, C : 3, D : 4}
for (let [key, value] of Object.entries(obj)){
obj[value] = key
delete obj[key]
}
console.log(obj) // {1: 'A', 2: 'B', 3: 'C', 4: 'D'}
ONE OF THE ES6 WAYS IS HERE
const invertObject = (object) =>Object.entries(object).reduce((result, value) => ({...result, [value[1]]: value[0] }), {});
let obj = invertObject({A : 1, B : 2, C : 3, D : 4});
Here's a type-safe way using TypeScript that has not been suggested before. This solution takes two generics that means the return type will be typed as expected. It's faster than doing methods with .reduce or Object.entries.
// Easier way to type `symbol | number | string` (the only valid keys of an object)
export type AnyKey = keyof any;
export function mirror<K extends AnyKey, V extends AnyKey>(
object: Record<K, V>,
) {
const ret: Partial<Record<V, K>> = {};
for (const key in object) {
ret[object[key]] = key;
}
return ret as Record<V, K>;
}
Usage:
const obj = mirror({
a: 'b',
c: 'd',
});
// {b: 'a', d: 'c'}
obj;
Modern JS solution:
const swapKeyValue = (object) =>
Object.entries(object).reduce((swapped, [key, value]) => (
{ ...swapped, [value]: key }
), {});
Typescript:
type ValidKey = number | string;
const swapKeyValue = <K extends ValidKey, V extends ValidKey>(
object: Record<K, V>
): Record<V, K> =>
Object.entries(object)
.reduce((swapped, [key, value]) => (
{ ...swapped, [value as ValidKey]: key }
), {} as Record<V, K>);
I believe it's better to do this task by using an npm module, like invert-kv.
invert-kv: Invert the key/value of an object. Example: {foo: 'bar'} → {bar: 'foo'}
https://www.npmjs.com/package/invert-kv
const invertKv = require('invert-kv');
invertKv({foo: 'bar', unicorn: 'rainbow'});
//=> {bar: 'foo', rainbow: 'unicorn'}

Javascript reduce() on Object

There is nice Array method reduce() to get one value from the Array. Example:
[0,1,2,3,4].reduce(function(previousValue, currentValue, index, array){
return previousValue + currentValue;
});
What is the best way to achieve the same with objects? I'd like to do this:
{
a: {value:1},
b: {value:2},
c: {value:3}
}.reduce(function(previous, current, index, array){
return previous.value + current.value;
});
However, Object does not seem to have any reduce() method implemented.
One option would be to reduce the keys():
var o = {
a: {value:1},
b: {value:2},
c: {value:3}
};
Object.keys(o).reduce(function (previous, key) {
return previous + o[key].value;
}, 0);
With this, you'll want to specify an initial value or the 1st round will be 'a' + 2.
If you want the result as an Object ({ value: ... }), you'll have to initialize and return the object each time:
Object.keys(o).reduce(function (previous, key) {
previous.value += o[key].value;
return previous;
}, { value: 0 });
What you actually want in this case are the Object.values. Here is a concise ES6 implementation with that in mind:
const add = {
a: {value:1},
b: {value:2},
c: {value:3}
}
const total = Object.values(add).reduce((t, {value}) => t + value, 0)
console.log(total) // 6
or simply:
const add = {
a: 1,
b: 2,
c: 3
}
const total = Object.values(add).reduce((t, n) => t + n)
console.log(total) // 6
ES6 implementation: Object.entries()
const o = {
a: {value: 1},
b: {value: 2},
c: {value: 3}
};
const total = Object.entries(o).reduce(function (total, pair) {
const [key, value] = pair;
return total + value.value;
}, 0);
First of all, you don't quite get what's reduce's previous value is.
In you pseudo code you have return previous.value + current.value, therefore the previous value will be a number on the next call, not an object.
Second, reduce is an Array method, not an Object's one, and you can't rely on the order when you're iterating the properties of an object (see: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Statements/for...in, this is applied to Object.keys too); so I'm not sure if applying reduce over an object makes sense.
However, if the order is not important, you can have:
Object.keys(obj).reduce(function(sum, key) {
return sum + obj[key].value;
}, 0);
Or you can just map the object's value:
Object.keys(obj).map(function(key) { return this[key].value }, obj).reduce(function (previous, current) {
return previous + current;
});
P.S. in ES6 with the fat arrow function's syntax (already in Firefox Nightly), you could shrink a bit:
Object.keys(obj).map(key => obj[key].value).reduce((previous, current) => previous + current);
1:
[{value:5}, {value:10}].reduce((previousValue, currentValue) => { return {value: previousValue.value + currentValue.value}})
>> Object {value: 15}
2:
[{value:5}, {value:10}].map(item => item.value).reduce((previousValue, currentValue) => {return previousValue + currentValue })
>> 15
3:
[{value:5}, {value:10}].reduce(function (previousValue, currentValue) {
return {value: previousValue.value + currentValue.value};
})
>> Object {value: 15}
An object can be turned into an array with: Object.entries(), Object.keys(), Object.values(), and then be reduced as array. But you can also reduce an object without creating the intermediate array.
I've created a little helper library odict for working with objects.
npm install --save odict
It has reduce function that works very much like Array.prototype.reduce():
export const reduce = (dict, reducer, accumulator) => {
for (const key in dict)
accumulator = reducer(accumulator, dict[key], key, dict);
return accumulator;
};
You could also assign it to:
Object.reduce = reduce;
as this method is very useful!
So the answer to your question would be:
const result = Object.reduce(
{
a: {value:1},
b: {value:2},
c: {value:3},
},
(accumulator, current) => (accumulator.value += current.value, accumulator), // reducer function must return accumulator
{value: 0} // initial accumulator value
);
Let me summarise the possibilities. The aim is always to make an array out of the object. There are various Javascript object functions for this. For each individual function, there are different ways of interpreting it. So it always depends on what our object looks like and what we want to do.
In the example above, it is an object with three objects.
const obj = {
a: {value: 1},
b: {value: 2},
c: {value:3}
};
With Object.keys
Object.keys only gives us the keys of the object.
const arr = Object.keys(obj);
// output arr:
[a, b, c]
const result = arr.reduce((total, key) => {
return sum + obj[key].value;
}, 0);
// output result
// 6
With Object.value
Object.value() returns the every single value in an array.
const arr = Object.value(obj);
// output arr
[
{value: 1},
{value: 2},
{value: 3},
]
const result = arr.reduce((total, singleValue) => {
return total + singleValue.value;
}, 0);
// output result
// 6
// Or the short variant
const resultShort = Object.values(obj).reduce((t, n) => t + n.value, 0)
// output resultShort
// 6
With Object.entries
Object.entries splits each individual object value into an array.
const arr = Object.entries(obj)
// output arr
[
["a", {visitors: 1}],
["b", {visitors: 2}],
["c", {visitors: 4}]
]
const result = arr.reduce((total, singleArr) => {
return total + singleArr[1].value;
}, 0);
// output result
// 6
Whether you do it with reduce or with the array function map() depends on you and what you want to do.
Extend Object.prototype.
Object.prototype.reduce = function( reduceCallback, initialValue ) {
var obj = this, keys = Object.keys( obj );
return keys.reduce( function( prevVal, item, idx, arr ) {
return reduceCallback( prevVal, item, obj[item], obj );
}, initialValue );
};
Sample of using.
var dataset = {
key1 : 'value1',
key2 : 'value2',
key3 : 'value3'
};
function reduceFn( prevVal, key, val, obj ) {
return prevVal + key + ' : ' + val + '; ';
}
console.log( dataset.reduce( reduceFn, 'initialValue' ) );
'Output' == 'initialValue; key1 : value1; key2 : value2; key3 : value3; '.
n'Joy it, guys!! ;-)
You can use a generator expression (supported in all browsers for years now, and in Node) to get the key-value pairs in a list you can reduce on:
>>> a = {"b": 3}
Object { b=3}
>>> [[i, a[i]] for (i in a) if (a.hasOwnProperty(i))]
[["b", 3]]
If you can use an array, do use an array, the length and order of an array are half its worth.
function reducer(obj, fun, temp){
if(typeof fun=== 'function'){
if(temp== undefined) temp= '';
for(var p in obj){
if(obj.hasOwnProperty(p)){
temp= fun(obj[p], temp, p, obj);
}
}
}
return temp;
}
var O={a:{value:1},b:{value:2},c:{value:3}}
reducer(O, function(a, b){return a.value+b;},0);
/* returned value: (Number)
6
*/
This is not very difficult to implement yourself:
function reduceObj(obj, callback, initial) {
"use strict";
var key, lastvalue, firstIteration = true;
if (typeof callback !== 'function') {
throw new TypeError(callback + 'is not a function');
}
if (arguments.length > 2) {
// initial value set
firstIteration = false;
lastvalue = initial;
}
for (key in obj) {
if (!obj.hasOwnProperty(key)) continue;
if (firstIteration)
firstIteration = false;
lastvalue = obj[key];
continue;
}
lastvalue = callback(lastvalue, obj[key], key, obj);
}
if (firstIteration) {
throw new TypeError('Reduce of empty object with no initial value');
}
return lastvalue;
}
In action:
var o = {a: {value:1}, b: {value:2}, c: {value:3}};
reduceObj(o, function(prev, curr) { prev.value += cur.value; return prev;}, {value:0});
reduceObj(o, function(prev, curr) { return {value: prev.value + curr.value};});
// both == { value: 6 };
reduceObj(o, function(prev, curr) { return prev + curr.value; }, 0);
// == 6
You can also add it to the Object prototype:
if (typeof Object.prototype.reduce !== 'function') {
Object.prototype.reduce = function(callback, initial) {
"use strict";
var args = Array.prototype.slice(arguments);
args.unshift(this);
return reduceObj.apply(null, args);
}
}
Try this one. It will sort numbers from other variables.
const obj = {
a: 1,
b: 2,
c: 3
};
const result = Object.keys(obj)
.reduce((acc, rec) => typeof obj[rec] === "number" ? acc.concat([obj[rec]]) : acc, [])
.reduce((acc, rec) => acc + rec)
If handled as an array is much easier
Return the total amount of fruits:
let fruits = [{ name: 'banana', id: 0, quantity: 9 }, { name: 'strawberry', id: 1, quantity: 1 }, { name: 'kiwi', id: 2, quantity: 2 }, { name: 'apple', id: 3, quantity: 4 }]
let total = fruits.reduce((sum, f) => sum + f.quantity, 0);
Since it hasnt really been confirmed in an answer yet, Underscore's reduce also works for this.
_.reduce({
a: {value:1},
b: {value:2},
c: {value:3}
}, function(prev, current){
//prev is either first object or total value
var total = prev.value || prev
return total + current.value
})
Note, _.reduce will return the only value (object or otherwise) if the list object only has one item, without calling iterator function.
_.reduce({
a: {value:1}
}, function(prev, current){
//not called
})
//returns {value: 1} instead of 1
Try out this one liner arrow function
Object.values(o).map(a => a.value, o).reduce((ac, key, index, arr) => ac+=key)

Categories

Resources