1

I have an array that looks something like this:

let result = [{"Person": "Bob","Wants":"Shoes"},
 {"Person": "Bob","Wants":"Socks"},
 {"Person": "Sam","Wants":"Coffee"},
 {"Person": "Tim","Wants":"Puppy"},
 {"Person": "Sam","Wants":"Biscuit"}];

I would like to convert it into an array that looks like this:

let summary  = [{"Person":"Bob","Wants":"Shoes, Socks"},
 {"Person":"Sam","Wants":"Coffee, Biscuit"},
 {"Person":"Tim","Wants":"Puppy"}];

I am very new to Javascript; it seems maybe I want to map or reduce the result array, but each time I try I get completely tied up in callbacks and foreach loops. Is there a simple way to join the strings in the second (Wants) column, when grouped by the first column?

High Plains Grifter
  • 1,357
  • 1
  • 12
  • 36
  • Very similar to https://stackoverflow.com/questions/19233283/sum-javascript-object-propertya-values-with-the-same-object-propertyb-in-an-arra - except append to “wants” array instead of summing. – James May 23 '23 at 13:27
  • 1
    `but each time I try` Just a polite notice, if you show what you tried it usually goes down better with SO users. The reason for this, in the long run showing were you maybe made a mistake will help you more, than people showing you ready made code. – Keith May 23 '23 at 13:28
  • `const res = Object.values(result.reduce((acc,{Person,Wants}) => { (acc[Person]??={Person,Wants:[]}).Wants.push(Wants); return acc; },{}))` now just map and join the Wants array with ", " – cmgchess May 23 '23 at 13:29
  • 1
    @Keith I hear you - part of the reason for finally giving up and asking the question is that the late-night rage quit did not include the "save all" that perhaps it should have... I had a look again this morning and it just seemed an even more tangled mess than ever and I thought... If I just take some advice for this one step I have a chance to have the mental fortitude to continue and sort out the rest of the scriptaghetti! It is not as similar to C# as I had thought..! – High Plains Grifter May 23 '23 at 13:31
  • 1
    `late-night rage` :), yeah, I'm sure we've all been there. Stick with it though, that scriptaghetti will hopefully transform into pure gold in the long run. If you haven't yet tried it, Typescript will certainly help on that journey.. – Keith May 23 '23 at 13:35

2 Answers2

4

const input = [{
    "Person": "Bob",
    "Wants": "Shoes"
  },
  {
    "Person": "Bob",
    "Wants": "Socks"
  },
  {
    "Person": "Sam",
    "Wants": "Coffee"
  },
  {
    "Person": "Tim",
    "Wants": "Puppy"
  },
  {
    "Person": "Sam",
    "Wants": "Biscuit"
  }
];

// a dictionary useful for later
const people = {}

// for each item of input
for (const { Person, Wants } of input) {
  if (!(Person in people)) {
    // if the person is not yet in the dictionary add them
    people[Person] = { Person, Wants: [] }
  }
  // add another item to Wants array
  people[Person].Wants.push(Wants)
}

// convert dictionary to a list
const result = Object.values(people)

// replace Wants array with string
for (const person of result) {
  person.Wants = person.Wants.join(', ')
}

console.log(result)
Konrad
  • 21,590
  • 4
  • 28
  • 64
  • 2
    I would say this is actually a better answer, using `foreach` / `map` , `reduce` etc is not always required, and because JS can scope with just a `{}`. Also this answer has commented the code, so gets my up-vote. – Keith May 23 '23 at 13:47
2

you can use forEach (or map) to see if the person in 'result' exists in 'summary' (assuming summary is an empty array to begin with), and if it does, add to that person's 'wants'.

let result = [
  {"Person": "Bob", "Wants": "Shoes"},
  {"Person": "Bob", "Wants": "Socks"},
  {"Person": "Sam", "Wants": "Coffee"},
  {"Person": "Tim", "Wants": "Puppy"},
  {"Person": "Sam", "Wants": "Biscuit"}
];

let summary = [];

result.forEach(item => {
  let existingPerson = summary.find(summaryItem => summaryItem.Person === item.Person);

  if (existingPerson) {
    existingPerson.Wants += `, ${item.Wants}`;
  } else {
    summary.push({"Person": item.Person, "Wants": item.Wants});
  }
});

DanWi
  • 50
  • 5