Kwhitejr
Kwhitejr

Reputation: 2306

How to reduce an array of objects on multiple variables in Javascript?

I would like to know how to reduce a large array of objects based upon several properties. The array looks like:

[{count:4, district:19, to_timestamp:"2015-09-24T00:00:00.000Z", type:"MOTOR VEHICLE THEFT"},
{count:6, district:12, to_timestamp:"2015-09-24T00:00:00.000Z", type:"MOTOR VEHICLE THEFT"},
{count:14, district:19, to_timestamp:"2015-10-01T00:00:00.000Z", type:"MOTOR VEHICLE THEFT"},
{count:4, district:19, to_timestamp:"2015-09-24T00:00:00.000Z", type:"VANDALISM"},
...
{count:4, district:19, to_timestamp:"2016-03-24T00:00:00.000Z", type:"MOTOR VEHICLE THEFT"},
{count:7, district:10, to_timestamp:"2016-03-24T00:00:00.000Z", type:"ASSAULT"}]

Resulting reduced array of objects needs to include the aggregate count from every district for given crime type on any given date (to_timestamp); dates are weekly. Something like:

[{key: "MOTOR VEHICLE THEFT", value: 57, date:"2015/09/23"},
...
  {key: "ASSAULT", value: 77, date:"2016/03/23"}]

I'm already using Moment for date conversions.

Upvotes: 2

Views: 1793

Answers (3)

孙欣乐
孙欣乐

Reputation: 426

but I think you reduce a object will be easier more then a array. after you got a object, you can convert it to a array

This code are just combine the data and type to the object key. Did not add district.

const object = [{count:4, district:19, to_timestamp:"2015-09-24T00:00:00.000Z", type:"MOTOR VEHICLE THEFT"},
{count:6, district:12, to_timestamp:"2015-09-24T00:00:00.000Z", type:"MOTOR VEHICLE THEFT"},
{count:14, district:19, to_timestamp:"2015-10-01T00:00:00.000Z", type:"MOTOR VEHICLE THEFT"},
{count:4, district:19, to_timestamp:"2015-09-24T00:00:00.000Z", type:"VANDALISM"},
{count:4, district:19, to_timestamp:"2016-03-24T00:00:00.000Z", type:"MOTOR VEHICLE THEFT"},
{count:7, district:10, to_timestamp:"2016-03-24T00:00:00.000Z", type:"ASSAULT"}]

// reduce a object 
.reduce( ( res, item) => {
  
  const date = moment(item.to_timestamp).format('YYYY/MM/DD')
  const key = item.type + date
  
  if ( !res[key] ) {
    res[key] = {key: item.type, date: date, value: item.count}
  } else {
    res[key]['value'] += item.count
  }
  return res
}, {} )

//get a object, and then the object to array
//console.log(object) 
var result = []
for ( var key in object ) {
  result.push(object[key])
}
console.log(result)
<script src="http://momentjs.com/downloads/moment.min.js"></script>

Upvotes: 2

Nina Scholz
Nina Scholz

Reputation: 386848

You could use an object as hash table for the wanted groups (type and to_timestamp) and use Array#forEach for iterating the array.

var data = [{ count: 4, district: 19, to_timestamp: "2015-09-24T00:00:00.000Z", type: "MOTOR VEHICLE THEFT" }, { count: 6, district: 12, to_timestamp: "2015-09-24T00:00:00.000Z", type: "MOTOR VEHICLE THEFT" }, { count: 14, district: 19, to_timestamp: "2015-10-01T00:00:00.000Z", type: "MOTOR VEHICLE THEFT" }, { count: 4, district: 19, to_timestamp: "2015-09-24T00:00:00.000Z", type: "VANDALISM" }, { count: 4, district: 19, to_timestamp: "2016-03-24T00:00:00.000Z", type: "MOTOR VEHICLE THEFT" }, { count: 7, district: 10, to_timestamp: "2016-03-24T00:00:00.000Z", type: "ASSAULT" }],
    groupBy = ['type', 'to_timestamp'],
    grouped = [];

data.forEach(function (a) {
    var key = groupBy.map(function (k) { return a[k]; }).join('|');
    if (!this[key]) {
        this[key] = { key: a.type, value: 0, date: a.to_timestamp.slice(0, 10).replace(/-/g, '/') };
        grouped.push(this[key]);
    }
    this[key].value += a.count;
}, Object.create(null));

console.log(grouped);

Upvotes: 5

Morteza Tourani
Morteza Tourani

Reputation: 3536

I think you can do this with a simple Array.prototype.forEach loop:

var crimes = [
	{count:4, district:19, to_timestamp:"2015-09-24T00:00:00.000Z", type:"MOTOR VEHICLE THEFT"},
	{count:6, district:12, to_timestamp:"2015-09-24T00:00:00.000Z", type:"MOTOR VEHICLE THEFT"},
	{count:14, district:19, to_timestamp:"2015-10-01T00:00:00.000Z", type:"MOTOR VEHICLE THEFT"},
	{count:4, district:19, to_timestamp:"2015-09-24T00:00:00.000Z", type:"VANDALISM"},
	{count:4, district:19, to_timestamp:"2016-03-24T00:00:00.000Z", type:"MOTOR VEHICLE THEFT"},
	{count:7, district:10, to_timestamp:"2016-03-24T00:00:00.000Z", type:"ASSAULT"}
];

var dict = {},
	result = [];
crimes.forEach(crime => {
	var date = new Date(crime.to_timestamp);
	date.setDate(date.getDate() - date.getDay());
	var hash = crime.type + date.toDateString()
	if (!dict[hash]) {
		dict[hash] = {
			count: crime.count,
			key: crime.type,
			date: date
		};
		result.push(dict[hash])
	} else
		dict[hash].count += crime.count;
});

console.log(result);

Upvotes: 0

Related Questions