На основании предоставленной вами информации я думаю, что это можно сделать с помощью одной функции уменьшения. Ключом является создание объекта, ключи которого сначала представляют уникальные разговоры, а затем выводят его в виде массива.
Примерно так:
let messages = [ ... ] // Your messages inside here
// We want to run a reducer on the messages array to get
// unique conversations, then user Object.values to transform
// this back into an array.
let output = Object.values(messages.reduce((acc, message) => {
// Convert both the sender and receiver ids to numbers.
let sender = Number(message.sender_id);
let receiver = Number(message.target.recipient_id);
// We always want the conversation ID to be the same, regardless
// of who the sender or receiver was, as long as it's the same
// participants. The code below will always generate a string with
// the smaller ID first, and the larger ID second, regardless of
// what role the users played in the message.
let conversation_id = sender > receiver
? `${receiver}_${sender}`
: `${sender}_${receiver}`;
if (acc[conversation_id]) {
// If the conversation already exists, then we will just add this message
// to the array of messages that make up the conversation
acc[conversation_id].push(message);
}
else {
// If the conversation doesn't exist, create a new array of messages
// with this conversation ID and the first message initializing the array.
acc[conversation_id] = [message];
}
// Return the updated accumulator, which will be used in the next
// iteration.
return acc;
}, {}));
Пока sender_id и receient_id являются числамиэто должно сработать.
Редактировать
Вот несколько простых объяснений частей, которые могут быть неясными.
Object.values
Эта функция будет работать по-разному в зависимости от того, какой аргумент вы ей предоставляете. Но в основном вы увидите, что это используется для извлечения массива значений из объекта (то есть {}
), а не из строки или массива, поскольку у них есть свои собственные методы для этого.
При разговорео значениях объекта, я имею в виду часть значения пар ключ / значение. Например:
let obj = {
a: 1 // 'a' is the key, 1 is the value
b: 2 // 'b' is the key, 2 is the value
};
let arrayOfValues = Object.values(obj); // Will return [1, 2]
Array.reduce
Функция уменьшения массива является очень мощным инструментом в арсенале программирования JavaScipt. Он принимает функцию в качестве аргумента и, необязательно, начальное значение для аккумулятора. Это похоже на forEach
с состоянием, в котором он выполняет функцию для каждого элемента в массиве, но поддерживает состояние (аккумулятор) на всех итерациях.
Вот простой редуктор ...
let initialState = 'abc';
let values = ['d', 'e', 'f']
let result = values.reduce((acc, val) => {
return acc + val;
}, initialState);
console.log(result) // 'abcdef';
.. и та же функциональность с простым forEach
циклом
let initialState = 'abc';
let values = ['d', 'e', 'f'];
let result = intialState;
values.forEach(value => {
result += value;
});
console.log(result) // 'abcdef';
Единственное отличие состоит в том, что данные о состоянии, используемые в цикле, содержатся и возвращаются изreduce
функция, где, как и во всех других циклах, вам нужно управлять состоянием из области за пределами самого цикла.
ternary operator
Тернарный оператор или что-то подобное существует в большом количестве языков. По сути, это быстрый способ написать оператор if else, целью которого является определение значения одной переменной. Выражение после части ?
оператора похоже на if
, а выражение после части :
похоже на else.
Вот простой троичный символ
let twenty = 20;
let isTwentyGreaterThanTen = twenty > 10 ? 'Yes' : 'No';
console.log(isTwentyGreayerThanTen); // 'Yes'
Аналогичная функциональность с оператором if/else
let twenty = 20;
let isTwentyGreaterThanTen;
if (twenty > 10) {
isTwentyGreaterThanTen = 'Yes';
}
else {
isTwentyGreaterThanTen = 'No';
}
console.log(isTwentyGreayerThanTen); // 'Yes'