In one of my projects there is a need to remove objects from on object array if the type property of those objects is the same and there are more than 2 consecutive objects with the same type in the array.
For example:
[
{
type: 'joined',
name: 'test',
},
{
type: 'joined',
name: 'test 1',
},
{
type: 'left',
name: 'test 2',
},
{
type: 'joined',
name: 'test 3',
},
{
type: 'joined',
name: 'test 4',
},
{
type: 'joined',
name: 'test 5',
},
{
type: 'joined',
name: 'test 6',
},
{
type: 'joined',
name: 'test 7',
}
]
Should result in:
[
{
type: 'joined',
name: 'test',
},
{
type: 'joined',
name: 'test 1',
},
{
type: 'left',
name: 'test 2',
}
]
So, the first 2 objects had the "joined" type but there are not more than 2 consecutive objects with that same type so they did not get removed. But the last 5 were removed as they all had the same type and there were more than 2 consecutive objects with that same type.
And the removed items should be collected into a separate array.
From Group same elements in JS array, but only when consecutive I have the following snippet:
const messages = [
{ message: "One", user: "Bob" },
{ message: "Two", user: "Bob" },
{ message: "Three", user: "Bob" },
{ message: "Hello", user: "Sam" },
{ message: "Hello", user: "Bob" },
{ message: "Hello", user: "Sam" },
{ message: "Hello", user: "Sam" }
]
let currentUser;
let groupedMessages = [];
for (message of messages) {
if (message.user !== currentUser) {
groupedMessages.push([]);
currentUser = message.user;
}
groupedMessages[groupedMessages.length - 1].push(message)
}
console.log(groupedMessages);
However it doesn't take into account the minimum threshold which is 2. Can anybody point me in the right direction as to how this can be modified to suit my needs?
CodePudding user response:
It is similar to grouping, but instead of creating an array of subarrays:
- Delay the push until it is certain the slice of duplicates is smaller than 3 elements
- Push to a one-dimensional array (using spread) instead of to a nested array.
Code:
const data = [{type: 'joined',name: 'test',},{type: 'joined',name: 'test 1',},{type: 'left',name: 'test 2',},{type: 'joined',name: 'test 3',},{type: 'joined',name: 'test 4',},{type: 'joined',name: 'test 5',},{type: 'joined',name: 'test 6',},{type: 'joined',name: 'test 7',}];
const result = [];
for (let i = 0; i < data.length; null) {
let start = i;
while (i < data.length && data[start].type === data[i].type) i ;
if (i - start < 3) result.push(...data.slice(start, i));
}
console.log(result);
CodePudding user response:
You can use an utility similar to python's itertools.groupby
which returns a sequence of consecutive series of "equal" objects:
function groups(data, fn) {
let last = {}, buf = []
for (let x of data) {
let curr = fn(x)
if (last === curr)
buf.at(-1).push(x)
else
buf.push([x])
last = curr
}
return buf
}
and in your main code:
result = []
for (let group of groups(data, x => x.type))
if (group.length < 3)
result.push(...group)
CodePudding user response:
[I] need to remove objects from on object array if the type property of those objects is the same and there are more than 2 consecutive objects with the same type in the array...
and the removed items should be collected into a separate array.
It sounds like you want to end up with two arrays: one with the objects that meet the criteria, and one with the other objects.
Below is a functional solution which will allow you to specify the target key for value comparison and the max number of allowed consecutive repeated values. It will return an object with two separate arrays: one which includes the objects that meet the criteria (on the selected
property) and another which includes the ones that don't (on the removed
property).
If anything in the code is not clear, feel free to leave a comment.
function filterMaxConsecutive (array, key, maxConsecutiveCount) {
const selected = [];
const removed = [];
// Start with an empty object. Every object has a unique reference identity,
// so no value will strictly equal this empty object:
let previous = {};
const group = [];
const finalizeGroup = () => {
(group.length > maxConsecutiveCount ? removed : selected).push(...group);
group.length = 0;
};
for (const o of array) {
const current = o[key];
if (current !== previous) finalizeGroup();
group.push(o);
previous = current;
}
finalizeGroup();
return {selected, removed};
}
const input = [{type:"joined",name:"test"},{type:"joined",name:"test 1"},{type:"left",name:"test 2"},{type:"joined",name:"test 3"},{type:"joined",name:"test 4"},{type:"joined",name:"test 5"},{type:"joined",name:"test 6"},{type:"joined",name:"test 7"}];
const result = filterMaxConsecutive(input, 'type', 2);
console.log(result);