6

I have an array of objects representing a series of 'messages' in a chat. I want to group messages that are consecutively created by the same 'user', which is stored in each array item. Here's a simplified version of what I'm trying to do:

[
    { 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" }
]

should be turned into:

[
    [
        { 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" }
    ]
]

Is there any easy way to do this? I couldn't find an answer/algorithm anywhere.

4 Answers 4

12

You can do that with the reduce method.

const data = [
  { 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" }
];

const result = data.reduce((acc, value) => {
  // compare the current value with the last item in the collected array
  if (acc.length && acc[acc.length - 1][0].user == value.user) {
    // append the current value to it if it is matching
    acc[acc.length - 1].push(value);
  } else {
    // append the new value at the end of the collected array
    acc.push([value]);
  }

  return acc;
}, []);
  
console.log(result);

Sign up to request clarification or add additional context in comments.

Comments

2

You could do something like this:

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

Comments

1

You could check the last element and if it has not the same user, then create a new array.

var data = [{ 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" }],
    grouped = data.reduce((r, o, i, a) => {
        if (!i || a[i - 1].user !== o.user) {
            r.push([]);
        }
        r[r.length - 1].push(o);
        return r;
    }, []);
    
console.log(grouped);

Comments

1

You can solve this with just Array.reduce and using its parameters for index of the array and the actual array:

const data = [{ 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" } ]

const group = d => d.reduce((r,c,i,a) => (a[i].user == (a[i-1] && a[i-1].user) 
 ? r[r.length-1].push(c) : r.push([c]), r), [])

console.log(Object.values(group(data)))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.