Related
for example look at this array, I want to remove those objects which the the value of their "age" is the same.
var array =[
{age:21,name:"sam",class="C"},
{age:24,name:"david",class="f"},
{age:45,name:"zack",class="f"},
{age:21,name:"jeff",class="g"},
{age:21,name:"marco",class="a"},
{age:26,name:"john",class="d"},
];
I want to get this result:
[
{age:21,name:"sam",class="C"},
{age:24,name:"david",class="f"},
{age:45,name:"zack",class="f"},
{age:26,name:"john",class="d"},
];
You can use reduce
var array = [
{age:21,name:"sam",class:"C"},
{age:24,name:"david",class:"f"},
{age:45,name:"zack",class:"f"},
{age:21,name:"jeff",class:"g"},
{age:21,name:"marco",class:"a"},
{age:26,name:"john",class:"d"}
];
let result = array.reduce((a,v) => {
let i = a.findIndex(person => person.age === v.age);
if(i !== -1){
return a;
}
return [...a, {...v}];
},[]);
console.log(result);
You can do this
var array =[
{age:21,name:"sam",class:"C"},
{age:24,name:"david",class:"f"},
{age:45,name:"zack",class:"f"},
{age:21,name:"jeff",class:"g"},
{age:21,name:"marco",class:"a"},
{age:26,name:"john",class:"d"},
];
var res = array.filter((i, index, self) => self.findIndex(k => k.age === i.age)==index);
console.log(res);
//Another clever way with lesser complexity :)
var res = array.reduce((a,v)=>{
if(!a[v.age]){
a[v.age] = v
};
return a
},{})
console.log(Object.values(res))
Example:
hash = {'Apple':2, 'Orange' :1 , 'Mango' : 2}
here the maximum key is both Apple and Mango. How do I write a function which gives both Apple and Mango as answer.
I tried something like this :
Object.keys(hash).reduce(function(a, b){ return hash[a] > hash[b] ? a : b });
But this gives only Apple as the answer.
You could first calculate the max value as a separate operation and then just filter:
const hash = {Apple: 2, Orange: 1, Mango: 2};
const max = Object.keys(hash).reduce((a, v) => Math.max(a, hash[v]), -Infinity);
const result = Object.keys(hash).filter(v => hash[v] === max);
console.log(result);
Simple and readable, but it requires and extra iteration, so it's not the most efficient implementation.
Your reduce can only return a single value, but you need an array of values. So create one as the initial value.
In your function body, first, check whether your next key has a larger value, in which case you clear out the array.
Then, if your array is empty, or if the first contained key (and thus all keys) have the same value, push that key into your array.
Also, it helps if you give your arguments more expressive names.
Object.keys(hash).reduce(function(longestKeys, key){
if(hash[key] > hash[longestKeys[0]]){
longestKeys.length = 0;
}
if(longestKeys.length === 0 || hash[key] === hash[longestKeys[0]]){
longestKeys.push(key);
}
return longestKeys;
}, []);
You might transform the object into one whose properties correspond to the count, whose values are the (original) property names in an array, and then get the value of the property with the maximum count:
const hash = {'Apple':2, 'Orange' :1 , 'Mango' : 2};
const indexedByCount = Object.entries(hash).reduce((a, [key, val]) => {
if (!a[val]) a[val] = [];
a[val].push(key);
return a;
}, {});
console.log(
indexedByCount[Math.max(...Object.keys(indexedByCount))]
);
A less functional but more efficient method would be to keep track of a max variable corresponding to the maximum value found so far:
const hash = {'Apple':2, 'Orange' :1 , 'Mango' : 2};
let max = -Infinity;
console.log(
Object.entries(hash).reduce((a, [key, val]) => {
if (val > max) {
max = val;
return [key];
}
if (val === max) a.push(key);
return a;
}, [])
);
This works. If max changes clear the result and set only the max value.
var hash = {'Apple':2, 'Orange':1 , 'Mango':2, "Jackfruit":10, "Pineapple":5, "Tomato":-4};
var max="";
var result = Object.keys(hash).reduce(function(acc, val){
if(max < hash[val]) (max=hash[val], acc={});
if(hash[val]==max) acc[val] = hash[val];
return acc;
},{});
console.log(result)
I believe the requirements are traverse the array only once and results is an array of keys
const hash = {'Apple':2, 'Orange' :1 , 'Mango' : 2};
let max = 0;
let result = [];
Object.getOwnPropertyNames(hash).forEach(k => {
if (hash[k] > max) {
result = [k];
max = hash[k];
} else if (hash[k] === max) {
result.push(k);
}
});
console.log(result);
if I have an object that looks like:
let object = {
name1 : {
number : .5,
otherVar : 'something'
},
name2 : {
number : .7,
otherVar : 'text'
},
name3 : {
number : -.1,
otherVar : 'some words'
}
};
how could I sort it by the number value and get an array:[ name3, name1, name2]?
Here is another es6 exampel:
let object = {
name1 : {
number : .5,
otherVar : 'something'
},
name2 : {
number : .7,
otherVar : 'text'
},
name3 : {
number : -.1,
otherVar : 'some words'
}
};
let k = Object.keys(object).sort(((a, b) => object[a].number > object[b].number));
console.log(k);
Here's a one liner:
Object.keys(object).map(key => object[key]).sort((a, b) => a.number - b.number)
let sorted = Object.keys(obj).map(key => obj[key]).sort((a, b) => a.number - b.number);
Explanation:
Object.keys(obj) will return an array of keys ['name1', 'name2'...]
.map will turn that array into an array of values
.sort takes a compare function and returns the sorted array (see documentation)
Recommendation: don't call your objects object :)
Make an array that contains the object properties with the names added to them:
var array = [];
for (var key in object) {
object[key].name = key;
array.push(object[key]);
}
Then sort that array by the number:
array.sort((a, b) => a.number - b.number);
Then get the names out of the array:
var sortedNames = array.map(e => e.name);
Full demo:
let object = {
name1 : {
number : .5,
otherVar : 'something'
},
name2 : {
number : .7,
otherVar : 'text'
},
name3 : {
number : -.1,
otherVar : 'some words'
}
};
var array = [];
for (var key in object) {
object[key].name = key;
array.push(object[key]);
}
array.sort((a, b) => a.number - b.number);
var sortedNames = array.map(e => e.name);
console.log(sortedNames);
var items = [];
items = JSON.parse(object);
}); //will give you an array
function compare(a,b) {
if (a.number < b.number)
return -1;
if (a.number > b.number)
return 1;
return 0;
}
items.sort(compare); //array will be sorted by number
It should do the dirty work, first you flat your object into an array of objects, then you create your custom compare function, finally sort, and voila!
var keys = Object.keys(object);
function compare(a,b) {
if (object[a].number < object[b].number)
return -1;
if (object[a].number > object[b].number)
return 1;
return 0;
}
var res = keys.sort(compare);
I have an array of objects like this:
var booksArray = [
{Id:1,Rate:5,Price:200,Name:"History"},
{Id:2,Rate:5,Price:150,Name:"Geographic"},
{Id:3,Rate:1,Price:75,Name:"Maths"},
{Id:4,Rate:2,Price:50,Name:"Statistics"},
{Id:5,Rate:3,Price:120,Name:"Drawing"},
{Id:6,Rate:2,Price:100,Name:"Arts"},
{Id:7,Rate:3,Price:110,Name:"Chemistry"},
{Id:8,Rate:4,Price:160,Name:"Biology"},
{Id:9,Rate:4,Price:90,Name:"Software Engineering"},
{Id:10,Rate:4,Price:80,Name:"Algorithm"},
{Id:11,Rate:1,Price:85,Name:"Urdu"},
{Id:12,Rate:1,Price:110,Name:"International Relations"},
{Id:13,Rate:1,Price:120,Name:"Physics"},
{Id:14,Rate:3,Price:230,Name:"Electronics"},
{Id:15,Rate:3,Price:250,Name:"Jihad"},
{Id:16,Rate:3,Price:200,Name:"Functional Programming"},
{Id:17,Rate:2,Price:190,Name:"Computer Science"},
{Id:18,Rate:2,Price:50,Name:"Problem solving Techniques"},
{Id:19,Rate:6,Price:150,Name:"C#"},
{Id:20,Rate:7,Price:250,Name:"ASP.Net"}
]
I am sorting it with this function:
function sortBy(key, reverse) {
var moveSmaller = reverse ? 1 : -1;
var moveLarger = reverse ? -1 : 1;
return function(a, b) {
if (a[key] < b[key]) {
return moveSmaller;
}
if (a[key] > b[key]) {
return moveLarger;
}
return 0;
};
}
booksArray.sort(sortBy('Rate', false))
console.log(JSON.stringify(booksArray))
And this is producing this result:
[
{Id:3,Rate:1,Price:75,Name:"Maths"},
{Id:11,Rate:1,Price:85,Name:"Urdu"},
{Id:12,Rate:1,Price:110,Name:"International Relations"},
{Id:13,Rate:1,Price:120,Name:"Physics"},
{Id:4,Rate:2,Price:50,Name:"Statistics"},
{Id:6,Rate:2,Price:100,Name:"Arts"},
{Id:17,Rate:2,Price:190,Name:"Computer Science"},
{Id:18,Rate:2,Price:50,Name:"Problem solving Techniques"},
{Id:5,Rate:3,Price:120,Name:"Drawing"},
{Id:7,Rate:3,Price:110,Name:"Chemistry"},
{Id:14,Rate:3,Price:230,Name:"Electronics"},
{Id:15,Rate:3,Price:250,Name:"Jihad"},
{Id:16,Rate:3,Price:200,Name:"Functional Programming"},
{Id:8,Rate:4,Price:160,Name:"Biology"},
{Id:9,Rate:4,Price:90,Name:"Software Engineering"},
{Id:10,Rate:4,Price:80,Name:"Algorithm"},
{Id:1,Rate:5,Price:200,Name:"History"},
{Id:2,Rate:5,Price:150,Name:"Geographic"},
{Id:19,Rate:6,Price:150,Name:"C#"},
{Id:20,Rate:7,Price:250,Name:"ASP.Net"}
]
You can see it is sorting on the Rate field which is fine. Now I want to resort again the parts of array without disturbing Rate sorting. I need output like this:
[
{Id:12,Rate:1,Price:110,Name:"International Relations"},
{Id:3,Rate:1,Price:75,Name:"Maths"},
{Id:13,Rate:1,Price:120,Name:"Physics"},
{Id:11,Rate:1,Price:85,Name:"Urdu"},
{Id:6,Rate:2,Price:100,Name:"Arts"},
{Id:17,Rate:2,Price:190,Name:"Computer Science"},
{Id:18,Rate:2,Price:50,Name:"Problem solving Techniques"},
{Id:4,Rate:2,Price:50,Name:"Statistics"},
{Id:7,Rate:3,Price:110,Name:"Chemistry"},
{Id:5,Rate:3,Price:120,Name:"Drawing"},
{Id:14,Rate:3,Price:230,Name:"Electronics"},
{Id:16,Rate:3,Price:200,Name:"Functional Programming"},
{Id:15,Rate:3,Price:250,Name:"Jihad"},
{Id:10,Rate:4,Price:80,Name:"Algorithm"},
{Id:8,Rate:4,Price:160,Name:"Biology"},
{Id:9,Rate:4,Price:90,Name:"Software Engineering"},
{Id:2,Rate:5,Price:150,Name:"Geographic"},
{Id:1,Rate:5,Price:200,Name:"History"},
{Id:19,Rate:6,Price:150,Name:"C#"},
{Id:20,Rate:7,Price:250,Name:"ASP.Net"}
]
Here you can see it is sorted on Rate as well as Name.
Why am I not doing sorting with multiple keys once and for all? Because I am creating a function which sorts the array of objects and can be called multiple times.
Example:
myarray.order('Rate') // single sort
myarray.order('Rate').order('Name') // multiple sort
I can use some more parameters in my function to track if array has already been sorted.
Sample Fiddle
Assuming that you already have bookArray sorted by Rate. It can be sorted on second level using following. Can be fine tuned better for easy usability.
var arr = bookArray;
var firstSortKey = 'Rate';
var secondSortKey = 'Name';
var count = 0 ;
var firstSortValue = arr[count][firstSortKey];
for(var i=count+1; i<arr.length; i++){
if(arr[i][firstSortKey]!==firstSortValue){
var data = arr.slice(count, i);
data = data.sort(function(a, b){
return a[secondSortKey]>b[secondSortKey];
});
var argsArray = [count, i-count];
argsArray.push.apply(argsArray, data);
Array.prototype.splice.apply(arr, argsArray);
count = i;
firstSortValue = arr[i][firstSortKey];
}
}
Fiddle Demo
Change your sortBy function to accept an array of keys. Something like:
function sortBy(keys, reverse) {
var moveSmaller = reverse ? 1 : -1;
var moveLarger = reverse ? -1 : 1;
var key = keys.shift();
return function(a, b) {
if (a[key] < b[key]) {
return moveSmaller;
}
if (a[key] > b[key]) {
return moveLarger;
}
return keys.length ? (sortBy(keys, reverse))(a, b) : 0;
};
}
booksArray.sort(sortBy(['Rate', 'Name'], false))
(Untested, jsfiddle is down for me)
Just for fun: here's a generic sorter for multiple levels of field values within an Array of Objects.
Syntax
XSort().create([arrOfObjects])
.orderBy(
{key: [keyname], [descending=0/1] },
{key: [keyname], [descending=0/1]},
... );
See jsFiddle for an example using booksArray.
function XSort() {
const multiSorter = sortKeys => {
if (!sortKeys || sortKeys[0].constructor !== Object) {
throw new TypeError("Provide at least one {key: [keyname]} to sort on");
}
return function (val0, val1) {
for (let sortKey of sortKeys) {
const v0 = sortKey.key instanceof Function
? sortKey.key(val0) : val0[sortKey.key];
const v1 = sortKey.key instanceof Function
? sortKey.key(val1) : val1[sortKey.key];
const isString = v0.constructor === String || v1.constructor === String;
const compare = sortKey.descending ?
isString ? v1.toLowerCase().localeCompare(v0.toLowerCase()) : v1 - v0 :
isString ? v0.toLowerCase().localeCompare(v1.toLowerCase()) : v0 - v1;
if ( compare !== 0 ) { return compare; }
}
};
}
const Sorter = function (array) {
this.array = array;
};
Sorter.prototype = {
orderBy: function(...sortOns) {
return this.array.slice().sort(multiSorter(sortOns));
},
};
return {
create: array => new Sorter(array)
};
}
I'd like to sum the values of an object.
I'm used to python where it would just be:
sample = { 'a': 1 , 'b': 2 , 'c':3 };
summed = sum(sample.itervalues())
The following code works, but it's a lot of code:
function obj_values(object) {
var results = [];
for (var property in object)
results.push(object[property]);
return results;
}
function list_sum( list ){
return list.reduce(function(previousValue, currentValue, index, array){
return previousValue + currentValue;
});
}
function object_values_sum( obj ){
return list_sum(obj_values(obj));
}
var sample = { a: 1 , b: 2 , c:3 };
var summed = list_sum(obj_values(a));
var summed = object_values_sum(a)
Am i missing anything obvious, or is this just the way it is?
It can be as simple as that:
const sumValues = obj => Object.values(obj).reduce((a, b) => a + b, 0);
Quoting MDN:
The Object.values() method returns an array of a given object's own enumerable property values, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).
from Object.values() on MDN
The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.
from Array.prototype.reduce() on MDN
You can use this function like that:
sumValues({a: 4, b: 6, c: -5, d: 0}); // gives 5
Note that this code uses some ECMAScript features which are not supported by some older browsers (like IE). You might need to use Babel to compile your code.
You could put it all in one function:
function sum( obj ) {
var sum = 0;
for( var el in obj ) {
if( obj.hasOwnProperty( el ) ) {
sum += parseFloat( obj[el] );
}
}
return sum;
}
var sample = { a: 1 , b: 2 , c:3 };
var summed = sum( sample );
console.log( "sum: "+summed );
For fun's sake here is another implementation using Object.keys() and Array.reduce() (browser support should not be a big issue anymore):
function sum(obj) {
return Object.keys(obj).reduce((sum,key)=>sum+parseFloat(obj[key]||0),0);
}
let sample = { a: 1 , b: 2 , c:3 };
console.log(`sum:${sum(sample)}`);
But this seems to be way slower: jsperf.com
If you're using lodash you can do something like
_.sum(_.values({ 'a': 1 , 'b': 2 , 'c':3 }))
Now you can make use of reduce function and get the sum.
const object1 = { 'a': 1 , 'b': 2 , 'c':3 }
console.log(Object.values(object1).reduce((a, b) => a + b, 0));
A regular for loop is pretty concise:
var total = 0;
for (var property in object) {
total += object[property];
}
You might have to add in object.hasOwnProperty if you modified the prototype.
Honestly, given our "modern times" I'd go with a functional programming approach whenever possible, like so:
const sumValues = (obj) => Object.keys(obj).reduce((acc, value) => acc + obj[value], 0);
Our accumulator acc, starting with a value of 0, is accumulating all looped values of our object. This has the added benefit of not depending on any internal or external variables; it's a constant function so it won't be accidentally overwritten... win for ES2015!
Any reason you're not just using a simple for...in loop?
var sample = { a: 1 , b: 2 , c:3 };
var summed = 0;
for (var key in sample) {
summed += sample[key];
};
http://jsfiddle.net/vZhXs/
let prices = {
"apple": 100,
"banana": 300,
"orange": 250
};
let sum = 0;
for (let price of Object.values(prices)) {
sum += price;
}
alert(sum)
I am a bit tardy to the party, however, if you require a more robust and flexible solution then here is my contribution. If you want to sum only a specific property in a nested object/array combo, as well as perform other aggregate methods, then here is a little function I have been using on a React project:
var aggregateProperty = function(obj, property, aggregate, shallow, depth) {
//return aggregated value of a specific property within an object (or array of objects..)
if ((typeof obj !== 'object' && typeof obj !== 'array') || !property) {
return;
}
obj = JSON.parse(JSON.stringify(obj)); //an ugly way of copying the data object instead of pointing to its reference (so the original data remains unaffected)
const validAggregates = [ 'sum', 'min', 'max', 'count' ];
aggregate = (validAggregates.indexOf(aggregate.toLowerCase()) !== -1 ? aggregate.toLowerCase() : 'sum'); //default to sum
//default to false (if true, only searches (n) levels deep ignoring deeply nested data)
if (shallow === true) {
shallow = 2;
} else if (isNaN(shallow) || shallow < 2) {
shallow = false;
}
if (isNaN(depth)) {
depth = 1; //how far down the rabbit hole have we travelled?
}
var value = ((aggregate == 'min' || aggregate == 'max') ? null : 0);
for (var prop in obj) {
if (!obj.hasOwnProperty(prop)) {
continue;
}
var propValue = obj[prop];
var nested = (typeof propValue === 'object' || typeof propValue === 'array');
if (nested) {
//the property is an object or an array
if (prop == property && aggregate == 'count') {
value++;
}
if (shallow === false || depth < shallow) {
propValue = aggregateProperty(propValue, property, aggregate, shallow, depth+1); //recursively aggregate nested objects and arrays
} else {
continue; //skip this property
}
}
//aggregate the properties value based on the selected aggregation method
if ((prop == property || nested) && propValue) {
switch(aggregate) {
case 'sum':
if (!isNaN(propValue)) {
value += propValue;
}
break;
case 'min':
if ((propValue < value) || !value) {
value = propValue;
}
break;
case 'max':
if ((propValue > value) || !value) {
value = propValue;
}
break;
case 'count':
if (propValue) {
if (nested) {
value += propValue;
} else {
value++;
}
}
break;
}
}
}
return value;
}
It is recursive, non ES6, and it should work in most semi-modern browsers. You use it like this:
const onlineCount = aggregateProperty(this.props.contacts, 'online', 'count');
Parameter breakdown:
obj = either an object or an array
property = the property within the nested objects/arrays you wish to perform the aggregate method on
aggregate = the aggregate method (sum, min, max, or count)
shallow = can either be set to true/false or a numeric value
depth = should be left null or undefined (it is used to track the subsequent recursive callbacks)
Shallow can be used to enhance performance if you know that you will not need to search deeply nested data. For instance if you had the following array:
[
{
id: 1,
otherData: { ... },
valueToBeTotaled: ?
},
{
id: 2,
otherData: { ... },
valueToBeTotaled: ?
},
{
id: 3,
otherData: { ... },
valueToBeTotaled: ?
},
...
]
If you wanted to avoid looping through the otherData property since the value you are going to be aggregating is not nested that deeply, you could set shallow to true.
Use Lodash
import _ from 'Lodash';
var object_array = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}];
return _.sumBy(object_array, 'c')
// return => 9
I came across this solution from #jbabey while trying to solve a similar problem. With a little modification, I got it right. In my case, the object keys are numbers (489) and strings ("489"). Hence to solve this, each key is parse. The following code works:
var array = {"nR": 22, "nH": 7, "totB": "2761", "nSR": 16, "htRb": "91981"}
var parskey = 0;
for (var key in array) {
parskey = parseInt(array[key]);
sum += parskey;
};
return(sum);
A ramda one liner:
import {
compose,
sum,
values,
} from 'ramda'
export const sumValues = compose(sum, values);
Use:
const summed = sumValues({ 'a': 1 , 'b': 2 , 'c':3 });
We can iterate object using in keyword and can perform any arithmetic operation.
// input
const sample = {
'a': 1,
'b': 2,
'c': 3
};
// var
let sum = 0;
// object iteration
for (key in sample) {
//sum
sum += (+sample[key]);
}
// result
console.log("sum:=>", sum);
A simple solution would be to use the for..in loop to find the sum.
function findSum(obj){
let sum = 0;
for(property in obj){
sum += obj[property];
}
return sum;
}
var sample = { a: 1 , b: 2 , c:3 };
console.log(findSum(sample));
function myFunction(a) { return Object.values(a).reduce((sum, cur) => sum + cur, 0); }
Sum the object key value by parse Integer. Converting string format to integer and summing the values
var obj = {
pay: 22
};
obj.pay;
console.log(obj.pay);
var x = parseInt(obj.pay);
console.log(x + 20);
function totalAmountAdjectives(obj) {
let sum = 0;
for(let el in obj) {
sum += el.length;
}
return sum;
}
console.log(totalAmountAdjectives({ a: "apple" }))
A simple and clean solution for typescrip:
const sample = { a: 1, b: 2, c: 3 };
const totalSample = Object.values(sample).reduce(
(total: number, currentElement: number) => total + currentElement
);
console.log(totalSample);
Good luck!