Rob Gleeson
Rob Gleeson

Reputation: 325

Merge elements in array of objects based on property

I have an array of objects. Each object has an amount and value property. If an object has the same amount value I would like to add that value to that object.

Here's an example array:

const array = [
  {
    "key": 1,
    "amount": 11,
    "value": "were"
  },
  {
    "key": 2,
    "amount": 6,
    "value": "locomotives"
  },
  {
    "key": 3,
    "amount": 5,
    "value": "They"
  },
  {
    "key": 4,
    "amount": 5,
    "value": "with"
  },
  {
    "key": 5,
    "amount": 4,
    "value": "used"
  }
]

I would like to transform this to resemble this:

const array = [
  {
    "key": 1,
    "amount": 11,
    "value": "were"
  },
  {
    "key": 2,
    "amount": 6,
    "value": "locomotives"
  },
  {
    "key": 3,
    "amount": 5,
    "value": "They, width"
  },
  {
    "key": 5,
    "amount": 4,
    "value": "used"
  }
]

I've tried reduce and map but I can't seem to get it to join,

Upvotes: 2

Views: 55

Answers (5)

Siva Kondapi Venkata
Siva Kondapi Venkata

Reputation: 11001

Use forEach loop and build an object. If the amount key already exist then append the value string.

const update = data => {
  const res = {};
  data.forEach(item => {
    res[item.amount] =
      item.amount in res
        ? {
            ...res[item.amount],
            value: `${res[item.amount].value}, ${item.value}`
          }
        : { ...item };
  });
  return Object.values(res);
};

const array = [
  {
    key: 1,
    amount: 11,
    value: "were"
  },
  {
    key: 2,
    amount: 6,
    value: "locomotives"
  },
  {
    key: 3,
    amount: 5,
    value: "They"
  },
  {
    key: 4,
    amount: 5,
    value: "with"
  },
  {
    key: 5,
    amount: 4,
    value: "used"
  }
];

console.log(update(array));

Upvotes: 0

StepUp
StepUp

Reputation: 38094

In each iteration of reduce method, we can add value if there is an already added value:

const result = array.reduce((a, c) => {
  a[c.amount] = a[c.amount] || c;
  if ((Object.keys(a).includes(c.amount.toString())) && (a[c.amount].value!= c.value))
      a[c.amount].value += ', ' + c.value;
  return a;
}, {});

An example:

const array = [
  {
    "key": 1,
    "amount": 11,
    "value": "were"
  },
  {
    "key": 2,
    "amount": 6,
    "value": "locomotives"
  },
  {
    "key": 3,
    "amount": 5,
    "value": "They"
  },
  {
    "key": 4,
    "amount": 5,
    "value": "with"
  },
  {
    "key": 5,
    "amount": 4,
    "value": "used"
  }
];

const result = array.reduce((a, c) => {
  a[c.amount] = a[c.amount] || c;
  if ((Object.keys(a).includes(c.amount.toString())) && (a[c.amount].value!= c.value))
      a[c.amount].value += ', ' + c.value;
  return a;
}, {});

console.log(result);

Upvotes: 0

Mister Jojo
Mister Jojo

Reputation: 22265

mine..

const array1 = 
      [ { key: 1, amount: 11, value: "were"        } 
      , { key: 2, amount:  6, value: "locomotives" } 
      , { key: 3, amount:  5, value: "They"        } 
      , { key: 4, amount:  5, value: "with"        } 
      , { key: 5, amount:  4, value: "used"        } 
      ] 


const array2 = array1.reduce((a,c)=>
                {
                let same = a.find(e=>e.amount===c.amount)
                if (same) same.value += ', '+c.value
                else a.push(c)
                return a
                },[])

console.log( array2 )

Upvotes: 0

Nick Parsons
Nick Parsons

Reputation: 50684

You can use .reduce() with an ES6 Map by indexing by the amount value. If an object's amount value already exists within the map, you can update its value to include the current objects value. If the amount value isn't in the map, you can set it as a key and the current object as the value. Lastly, you can use Array.from() to get an array of object values from the iterator returned by .values()

const array = [ { "key": 1, "amount": 11, "value": "were" }, { "key": 2, "amount": 6, "value": "locomotives" }, { "key": 3, "amount": 5, "value": "They" }, { "key": 4, "amount": 5, "value": "with" }, { "key": 5, "amount": 4, "value": "used" } ];

const res = Array.from(array.reduce((m, o) => {
  const curr = m.get(o.amount);
  return m.set(o.amount, curr && {...curr, value: `${curr.value}, ${o.value}`} || o);
}, new Map).values());
console.log(res);

Upvotes: 1

norbitrial
norbitrial

Reputation: 15166

I think should work with .reduce():

const array = [
  {
    "key": 1,
    "amount": 11,
    "value": "were"
  },
  {
    "key": 2,
    "amount": 6,
    "value": "locomotives"
  },
  {
    "key": 3,
    "amount": 5,
    "value": "They"
  },
  {
    "key": 4,
    "amount": 5,
    "value": "with"
  },
  {
    "key": 5,
    "amount": 4,
    "value": "used"
  }
];

const result = array.reduce((a, c) => {
  const found = a.find(e => e.amount === c.amount);  
  if (found) found.value = `${found.value}, ${c.value}`;
  return found ? a : a.concat(c);
}, []);

console.log(result);

I hope that helps!

Upvotes: 1

Related Questions