2

So I have this object, and have to merge it with same selectionID, but also keep the topicName (and not overwrite it)

[
   {
      "selectionId":1,
      "topicName":"topic created or not validate"
   },
   {
      "selectionId":1,
      "topicName":"hghhhg test test"
   },
   {
      "selectionId":2,
      "topicName":"topic test"
   },
   {
      "selectionId":3,
      "topicName":"new topic for test topic name and description name(test check)"
   },
   {
      "selectionId":4,
      "topicName":"topic check check"
   },
   {
      "selectionId":4,
      "topicName":"topic check popup"
   },
   {
      "selectionId":5,
      "topicName":"test"
   }
]

Now I want to merge the selectioId, but also append the topicName to a new array in the same object so that I can loop it to display accordingly.

[
   {
      "selectionId":1,
      ["topicName":"topic created or not validate", "topicName":"hghhhg test test"] 
   }
   {
      "selectionId":2,
      "topicName":"topic test"
   }{
      "selectionId":3,
      "topicName":"new topic for test topic name and description name(test check)"
   }{
      "selectionId":4,
      ["topicName":"topic check check","topicName":"topic check popup"]
   }{
      "selectionId":5,
      "topicName":"test"
   }
]

I have tried this:

  var result = list.filter(function(v) {
        return this[v.selectionId]?
          !Object.assign(this[v.selectionId], v):
          (this[v.selectionId] = v);
      }, {});

Answer: (It does not take the topicName)

[
{selectionId: 1, topicName: "hghhhg test test"}
{selectionId: 2, topicName: "topic test"}
{selectionId: 3, topicName: "new topic for test topic name and description name(test check)"}
{selectionId: 4, topicName: "topic check popup"}
{selectionId: 5, topicName: "test"}
]

EDIT: Thank you guys! All the answers have worked! And giving results as expected.

nihar
  • 23
  • 1
  • 5
  • Possible duplicate of https://stackoverflow.com/questions/14446511/most-efficient-method-to-groupby-on-an-array-of-objects . Please have a look. – Snehasish Karmakar Aug 27 '21 at 14:52
  • This `["topicName":"topic check check","topicName":"topic check popup"]` kind of data type isn't valid, do you mean ? ` [{"topicName":"topic check check"},{"topicName":"topic check popup"}]` – tsamridh86 Aug 27 '21 at 14:52
  • 1
    I assume whent you write `["topicName":"topic check check","topicName":"topic check popup"]` what you really mean is `topicName: ["topic check check", "topic check popup"]`; may I ask you to amend the question, please? – secan Aug 27 '21 at 14:52
  • Use **Array.map** to create a brand new array for what you need. **filter** will keep your data **IF** your return stat is true. – Patfreeze Aug 27 '21 at 14:56

3 Answers3

1

You're example includes invalid syntax for an array.

["topicName":"topic check check","topicName":"topic check popup"]

This could be an array of objects:

[{"topicName":"topic check check"},{"topicName":"topic check popup"}]

Or more likely (how my example is based):

topicName: ["topic check check", "topic check popup"]

Because it is not a one-to-one input to output, it is a good use of Array.prototype.reduce.

list.reduce((acc, row) => {
  const existingSel = acc.find(e => e.selectionId === row.selectionId);
  
  // If we don't have an entry, make one.
  if (!existingSel) {
    // Use expansion of row to avoid mutating source objects
    return [ ...acc, { ...row}];
  }
  
  if (Array.isArray(existingSel.topicName)) {
    // if the topicName is an array, add to it.
    existingSel.topicName.push(row.topicName);
  } else {
    // Otherwise, make it an array with the two options.
    existingSel.topicName = [existingSel.topicName, row.topicName];
  }
  return acc;
}, []);
Sam R
  • 696
  • 3
  • 7
0

You can use Array.reduce() to arrange the output according to selectionId. The output array contains objects each with a selectionId and topics array.

        
const input = [ { "selectionId":1, "topicName":"topic created or not validate" },{ "selectionId":1, "topicName":"hghhhg test test" },{ "selectionId":2, "topicName":"topic test" },{ "selectionId":3, "topicName":"new topic for test topic name and description name(test check)" },{ "selectionId":4, "topicName":"topic check check" },{ "selectionId":4, "topicName":"topic check popup" },{ "selectionId":5, "topicName":"test" } ]

const output = Object.values(input.reduce((acc, cur) => { 
    acc[cur.selectionId] = acc[cur.selectionId] || { selectionId: cur.selectionId, topics: []};
    acc[cur.selectionId].topics.push({ topicName: cur.topicName});
    return acc;
}, {}))

console.log('Output:', output); 
Terry Lennox
  • 29,471
  • 5
  • 28
  • 40
0

If I got right what you expect as output, you can do:

const input = [{
  "selectionId": 1,
  "topicName": "topic created or not validate"
}, {
  "selectionId": 1,
  "topicName": "hghhhg test test"
}, {
  "selectionId": 2,
  "topicName": "topic test"
}, {
  "selectionId": 3,
  "topicName": "new topic for test topic name and description name(test check)"
}, {
  "selectionId": 4,
  "topicName": "topic check check"
}, {
  "selectionId": 4,
  "topicName": "topic check popup"
}, {
  "selectionId": 5,
  "topicName": "test"
}];

const output = input.reduce((acc, item) => {
  const element = acc.find(elem => elem.selectionId === item.selectionId)

  if (element) {
    element.topicName = Array.isArray(element.topicName) ?
      element.topicName.push(item.topicName) :
      [element.topicName, item.topicName]
  } else {
    acc.push(item)
  }

  return acc;
}, []);

// test
console.log(output);

Anyway I would advise you against having different data types for topicName and keep it an array even if it contains just one value:

const input = [{
  "selectionId": 1,
  "topicName": "topic created or not validate"
}, {
  "selectionId": 1,
  "topicName": "hghhhg test test"
}, {
  "selectionId": 2,
  "topicName": "topic test"
}, {
  "selectionId": 3,
  "topicName": "new topic for test topic name and description name(test check)"
}, {
  "selectionId": 4,
  "topicName": "topic check check"
}, {
  "selectionId": 4,
  "topicName": "topic check popup"
}, {
  "selectionId": 5,
  "topicName": "test"
}];

const betterOutput = input.reduce((acc, item) => {
  const element = acc.find(elem => elem.selectionId === item.selectionId);

  if (element) {
    element.topicName.push(item.topicName);
  } else {
    acc.push({
      selectionId: item.selectionId,
      topicName: [item.topicName]
    })
  }

  return acc;
}, []);

// test
console.log(betterOutput);
secan
  • 2,622
  • 1
  • 7
  • 24