2

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.

3 Answers 3

5

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);

Sign up to request clarification or add additional context in comments.

2 Comments

Can't say that I fully understand it (yet), but it sure does work. Mahalo. Are you able to explain a bit about what is happening on line: var key = groupBy.map(function (k) { return a[k]; }).join('|');
this line builds a new key with the values of the properties, defined in groupBy. for example for the first element, you get for the first property type the value "MOTOR VEHICLE THEFT" and for to_timestamp the value "2015-09-24T00:00:00.000Z" in an array. this is then joined with | and the result for the key is "MOTOR VEHICLE THEFT|2015-09-24T00:00:00.000Z". this result is used as hash for the object.
2

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>

1 Comment

Thank you for the reduce -based answer!
0

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);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.