arunmmanoharan
arunmmanoharan

Reputation: 2675

Reduce Array based on properties of 2 keys

I have an array like this.

var data = [{
  name: 'Apple',
  category: 'Fruit',
  value: 12
}, {
  name: 'Apple',
  category: 'Fruit',
  value: 20
}, {
  name: 'Orange',
  category: 'Fruit',
  value: 65
}, {
  name: 'Orange',
  category: 'Fruit',
  value: 40
}]

I need to get an array like this:

var newData = [{
  name: 'Apple',
  category: 'Fruit',
  value: 20
}, {
  name: 'Orange',
  category: 'Fruit',
  value: 65
}]

That is get the highest value for each 'name' key in an array.

This is what I have tried:

var data = [{
  name: 'Apple',
  category: 'Fruit',
  value: 12
}, {
  name: 'Apple',
  category: 'Fruit',
  value: 20
}, {
  name: 'Orange',
  category: 'Fruit',
  value: 65
}, {
  name: 'Orange',
  category: 'Fruit',
  value: 40
}]

console.log(data.reduce(function(prev, current) {
  return (prev.name !== current.name && prev.value > current.value) ? prev : current
}))

Please advice.

Upvotes: 0

Views: 887

Answers (4)

Monica Acha
Monica Acha

Reputation: 1086

var data = [{
  name: 'Apple',
  category: 'Fruit',
  value: 12
}, {
  name: 'Apple',
  category: 'Fruit',
  value: 20
}, {
  name: 'Orange',
  category: 'Fruit',
  value: 65
}, {
  name: 'Orange',
  category: 'Fruit',
  value: 40
}]
let result=data.reduce(function(temp, current) {
  //check if temp has object
  var found = temp.some((el) => {
      return el.name === current.name
    });
  //if not found, add the object
    if (!found) { temp.push(current) }
  //if found and value is greater, replace the max value
  else{
    temp.find((element) => {
     if(element.name === current.name && element.value<current.value)
    element.value=current.value
    })
  }
  return temp
},[])
console.log(result);

Upvotes: 0

Ramesh
Ramesh

Reputation: 13266

Use forEach instead of reduce

var data = [{
  name: 'Apple',
  category: 'Fruit',
  value: 12
}, {
  name: 'Apple',
  category: 'Fruit',
  value: 20
}, {
  name: 'Orange',
  category: 'Fruit',
  value: 65
}, {
  name: 'Orange',
  category: 'Fruit',
  value: 40
}]

let result = {};
data.forEach(function(current) {
  if (result[current.name] &&
    result[current.name].value < current.value &&
    result[current.name].category === current.category) {
    result[current.name].value = current.value;
  } else if (!result[current.name]) {
    result[current.name] = current;
  }
});
console.log(Object.values(result));

Upvotes: 0

brk
brk

Reputation: 50291

Use reduce and check if the accumulator array has the same fruit using findIndex . If it is -1 , then in accumulator array push the value else update the count in that index

var data = [{
  name: 'Apple',
  category: 'Fruit',
  value: 12
}, {
  name: 'Apple',
  category: 'Fruit',
  value: 20
}, {
  name: 'Orange',
  category: 'Fruit',
  value: 65
}, {
  name: 'Orange',
  category: 'Fruit',
  value: 40
}]



let result = data.reduce(function(acc, curr) {

  let findIfExist = acc.findIndex(elem => {
    return elem.name === curr.name;
  })
  if (findIfExist === -1) {
    acc.push(curr)
  } else {
    if (acc[findIfExist].value < curr.value) {
      acc[findIfExist].value = curr.value
    }

  }

  return acc;

}, [])

console.log(result)

Upvotes: 0

CertainPerformance
CertainPerformance

Reputation: 370679

You need to keep track of the current highest value items for every name, so you could try reducing into an object, whose keys are the names, and values are the currently winning values for that name. Then, get the resulting object's values:

var data = [{
  name: 'Apple',
  category: 'Fruit',
  value: 12
}, {
  name: 'Apple',
  category: 'Fruit',
  value: 20
}, {
  name: 'Orange',
  category: 'Fruit',
  value: 65
}, {
  name: 'Orange',
  category: 'Fruit',
  value: 40
}];

console.log(Object.values(
  data.reduce((a, item) => {
    const { name, value } = item;
    if (!a[name] || a[name].value < value) a[name] = item;
    return a;
  }, {})
));

(Your prev.name !== current.name ... method would only work if you're only trying to get one item out of it in the end - because you need more, you need an object that can contain multiple items.)

Upvotes: 4

Related Questions