0

I have an array

[
  { price: 10 },
  { price: 10 },
  { price: 10 },
  { price: 10 },
  { price: 20 },
  { price: 20 },
]

and I want it transformed into

[
  { numElements: 4, price: 10 },
  { numElements: 2, price: 20 },
]

I have tried using arr.reduce((prev, curr) => ..., []) to accomplish this, but I can't figure out how to do it.

2
  • Can you show the attempt with reduce? Using that is a very good start (not being condescending). Commented Aug 7, 2017 at 15:49
  • Possible duplicate of How to group an array of objects by key Commented Dec 19, 2018 at 17:42

5 Answers 5

0

A traditional method might use a for/loop to wrangle the data, but these days JavaScript has a number of functional methods that can help. This code uses reduce and map. To get your data in the format you want is a two stage process.

First, use reduce to create a hash table using the price as a key (because you know the each price is going to be unique:

const obj = arr.reduce((p, c) => {

  // If price exists as a key its value by 1
  // otherwise set it to 1.
  p[c.price] = ++p[c.price] || 1;
  return p;
}, {});

OUTPUT

{
  "10": 4,
  "20": 2
}

As it stands you've got a perfectly good object that you can access by the key/price and I would probably just stop there:

obj['10'] // 4

But if you want to get that data into the format in your question, map over the object keys to return an array of new objects.

const out = Object.keys(obj).map(key => {
  return { price: +key, numElements: obj[key] };
});

DEMO

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

Comments

0
var hash = {}, result = [];

 arr.forEach(function(el){
   if(hash[el.price]){
     hash[el.price].numElements++;
   }else{
     result.push(hash[el.price]={price:el.price,numElements:1});
  }
});

Run

May use a hash table for price lookup. Or with reduce and find:

 arr.reduce((res,{price})=>
  (( res.find(el=>el.price===price) || res[res.push({price,numElements:0})-1] )
  .numElements++,res)
);

Run

Comments

0

You can use try this:

let arr = [
  { price: 10 },
  { price: 10 },
  { price: 10 },
  { price: 10 },
  { price: 20 },
  { price: 20 },
]

let result = []

let counter = {}

arr.forEach( el => {

  if (!counter[el.price]) counter[el.price] = 1
  else counter[el.price]++

  console.log(counter[el.price])

})

for (let id in counter) {
  result.push({numElements: counter[id], price: id})
}

Comments

0

Assuming that the data comes sorted on price property, with a single .reduce() you may do as follows;

var data   = [{ price: 10 }, { price: 10 }, { price: 10 }, { price: 10 }, { price: 20 }, { price: 20 }],
    result = data.reduce((r,d,i) => i ? r[r.length-1].price === d.price ? (r[r.length-1].numElemenets++, r)
                                                                        : (r.push(Object.assign({}, d, {numElemenets: 1})),r)
                                      : [Object.assign({}, d, {numElemenets: 1})], {});
console.log(result);

Comments

0

You could look up the price in the result array and if not found insert a new object.

var data = [{ price: 10 }, { price: 10 }, { price: 10 }, { price: 10 }, { price: 20 }, { price: 20 }],
    grouped = data.reduce((r, { price }) => {
        var t = r.find(p => price === p.price);
        t || r.push(t = { numElements: 0, price });
        t.numElements++;
        return r;
    }, []);
    
console.log(grouped);

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.