I have a json where I need to reduce the items when they are of a type (isSender
).
I need to reduce them when they are occurring consecutively.
The data can change.
The data looks like this:
"messages": [
{ "content": ["Foo"], "isSender": true },
{ "content": ["Bar"], "isSender": true },
{ "content": ["Lorem"], "isSender": true },
{ "content": ["Ipsum"], "isSender": true },
{ "content": ["Dolor"], "isSender": false },
{ "content": ["Sit Amet"], "isSender": false },
{ "content": ["No"], "isSender": true }
]
I need the content to be an array of messages when the consecutive isSender
key is the same. The output should look like this:
"messages": [
{
"content": ["Foo", "Bar", "Lorem", "Ipsum"],
"isSender": true
},
{ "content": ["Dolor", "Sit amet"], "isSender": false },
{ "content": ["No"], "isSender": true }
]
So far I have tried looping through the message array and checking if next messages have the same isSender
key. However this does not work for more than 2 messages.
let deleteIndex = [];
for(let i = 0 ; i < messages.length - 1; i ) {
const currMs = messages[i];
const nextMs = messages[i 1];
if (nextMs.isSender == currMs.isSender) {
currMs.content.push(nextMs)
deleteIndex.push(i 1) // saving index to be deleted once for loop is done
}
}
Can someone give me a clue on how to work around this?
Thanks in advance.
CodePudding user response:
Use reduce()
, on each iteration, we check if the last element in the result array has the same isSender
value as the current object we're dealing with.
if (p.length && p.at(-1).isSender === c.isSender) {
So, if
we already have something in the final array (p.length
) AND the last isSender
(p.at(-1).isSender
) has the same value as the current isSender
(c.isSender
), append to that content
list
Otherwise, add the entry, which is just the current object itself (return [ ...p, c ]
)
const data = [
{ "content": ["Foo"], "isSender": true },
{ "content": ["Bar"], "isSender": true },
{ "content": ["Lorem"], "isSender": true },
{ "content": ["Ipsum"], "isSender": true },
{ "content": ["Dolor"], "isSender": false },
{ "content": ["Sit Amet"], "isSender": false },
{ "content": ["No"], "isSender": true }
];
const res = data.reduce((p, c) => {
if (p.length && p.at(-1).isSender === c.isSender) {
p.at(-1).content.push(...c.content);
return p;
}
return [ ...p, c ];
}, [])
console.log(res);
[
{
"content": ["Foo", "Bar", "Lorem", "Ipsum"],
"isSender": true
},
{
"content": ["Dolor", "Sit Amet"],
"isSender": false
},
{
"content": ["No"],
"isSender": true
}
]
CodePudding user response:
you can try this
JArray jArr = JObject.Parse(json)["messages"] as JArray;
var noContent = jArr.Select(a => a)
.Where(a => string.Join(",", a["content"]) == "No")
.FirstOrDefault();
jArr.Remove(noContent);
var jObj = new JObject
{
["messages"] = new JArray(jArr.GroupBy(x => x["isSender"])
.Select(g => new JObject
{
["content"] = new JArray(g.SelectMany(y => y["content"])),
["isSender"] = g.Key
}))
};
((JArray)jObj["messages"]).Add(noContent);
json = jObj.ToString();
//or if you create a Messages class
Messages messages = jObj.ToObject<Messages>();
json output
{
"messages": [
{
"content": [
"Foo",
"Bar",
"Lorem",
"Ipsum"
],
"isSender": true
},
{
"content": [
"Dolor",
"Sit Amet"
],
"isSender": false
},
{
"content": [
"No"
],
"isSender": true
}
]
}