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.
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;
}, []);
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);
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);