简体   繁体   中英

Remove consecutive objects with the same type property from object array

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?

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);

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 groups 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);

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM