0

How do I count the prices together from the following array of objects:

const cars = [
{
    price: 10000,
    car: 'audi'
},
{
    price: 10000,
    car: 'audi'
},
{
    price: 10000,
    car: 'nissan'
},
{
    price: 10000,
    car: 'nissan'
},
{
    price: 20000,
    car: 'mazda'
},
{
    price: 10000,
    car: 'nissan'
},
];

So that I would get an array of objects, with the total prices:

const cars = [
{
    price: 20000,
    car: 'audi'
},
{
    price: 30000,
    car: 'nissan'
},
{
    price: 20000,
    car: 'mazda'
}
];

Tried to map over the array, and then reduce, but how do i keep the structure, so that I get back an array of objects? This is incorrect:

 const newCarsArray = cars.map(item => {
     return(
        //cars.reduce ?
     )
 });
kukkuz
  • 41,512
  • 6
  • 59
  • 95
userden
  • 1,615
  • 6
  • 26
  • 50
  • Possible duplicate of [Access / process (nested) objects, arrays or JSON](https://stackoverflow.com/questions/11922383/access-process-nested-objects-arrays-or-json) – Liam Aug 11 '17 at 14:20
  • 3
    I don't think this is a duplicate of this question. – mdziekon Aug 11 '17 at 14:22
  • So loop over and make a hash with the values and than convert that hash back into an array. – epascarello Aug 11 '17 at 14:23

6 Answers6

1

You could reduce, however a simple forEach in conjunction with a hashtable does it:

var companies = {}, result = [];

cars.forEach(function(el){
 if(companies[el.car]){
   companies[el.car].price += el.price;
 }else{
   result.push( companies[el.car] = Object.assign({},el));
 }
});

A reduce approach would look like this:

var result = cars.reduce((res,el)=> (
   ( 
     res.find(c => c.car === el.car ) 
     || res[res.push({price:0,car:el.car})-1] 
   ).price += el.price,res
),[]);
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
1

You can reduce your array to an object keyed by car, holding the total, then it's pretty simple to convert that back to your format

const cars = [{price: 10000, car: 'audi'},{price: 10000, car: 'audi'},{price: 10000, car: 'nissan'},{price: 10000, car: 'nissan'}, {price: 20000,        car: 'mazda'}, {price: 10000, car: 'nissan'}];

var map = cars.reduce((map, car) => {
  map[car.car] = map[car.car] ? map[car.car] + car.price : car.price;
  return map;
}, {});

console.log(map); // {audi: 20000, nissan: 30000, mazda: 20000}

var array = Object.keys(map).map( car => ({car: car, price: map[car]}));

console.log(array);
Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
0

Here's the two-stage reduce then map process.

First get an object with the car name as the unique keys, the price as the value:

var obj = cars.reduce((p, c) => {
  const key = c.car;

  // If the key doesn't exist create it
  // and set the value to zero
  p[key] = p[key] || 0;
  p[key] += c.price;
  return p;
}, {});

Then map over the keys of that object to produce a new array of objects:

var out = Object.keys(obj).map(p => {
  return { price: p, car: obj[p] };
});

DEMO

Andy
  • 61,948
  • 13
  • 68
  • 95
0

First create a hashtable with the unique objects and accumulated price and then use #map() to group them up - see demo below:

const cars=[{price:10000,car:'audi'},{price:10000,car:'audi'},{price:10000,car:'nissan'},{price:10000,car:'nissan'},{price:20000,car:'mazda'},{price:10000,car:'nissan'},];

// create a hash first, and accumulate price
var hash = cars.reduce(function(p,c) {
  if(p[c.car]) {
    p[c.car].price += c.price;
  } else {
    p[c.car] = c;
  }
  return p;
}, Object.create(null));

// now convert to array
var result = Object.keys(hash).map(function(e){
  return hash[e];
});

console.log(result);
.as-console-wrapper{top:0;max-height:100%!important;}
kukkuz
  • 41,512
  • 6
  • 59
  • 95
0

const cars = [
{
    price: 10000,
    car: 'audi'
},
{
    price: 10000,
    car: 'audi'
},
{
    price: 10000,
    car: 'nissan'
},
{
    price: 10000,
    car: 'nissan'
},
{
    price: 20000,
    car: 'mazda'
},
{
    price: 10000,
    car: 'nissan'
},
];

const result = Object.values(cars.reduce((prices, carInfo) => {
  if (prices.hasOwnProperty(carInfo.car)) {
    prices[carInfo.car].price += carInfo.price;
  } else {
    prices[carInfo.car] = Object.assign(carInfo);
  }
  return prices;
}, {}));

console.log(result);
PeterMader
  • 6,987
  • 1
  • 21
  • 31
0

This can be achieved using a Array.prototype.reduce() method just as you said:

function groupAndSumCars(elements) {
    return elements.reduce(function (accumulator, element) {
        // Check if a group for that car already exists,
        // ".find()" returns undefined if nothing has been found
        const groupElement = accumulator.find(function (group) {
            return group.car === element.car;
        });

        // Group not created yet, create a new one
        if (!groupElement) {
            accumulator.push(element);

            return accumulator;
        }

        // Group already exists, increment "price" counter
        groupElement.price += element.price;

        return accumulator;
    }, []);
}

If you care about the performance, you should replace the .find() piece with something more performant (for example, you could use a temporary object to store group elements, or create a temporary Map).

mdziekon
  • 3,531
  • 3
  • 22
  • 32