Группировка и фильтрация массива по нескольким признакам JS
Дан некий массив объектов:
const arr = [
{
method: 1,
currency: 'RUB',
amount: 10,
priority: 1,
},
{
id: 22,
method: 1,
currency: 'RUB',
amount: 100,
priority: 1,
},
{
id: 25,
method: 1,
currency: 'RUB',
amount: 49,
priority: 1,
},
{
id: 33,
method: 1,
currency: 'USD',
amount: 55,
priority: 1,
},
{
id: 77,
method: 1,
currency: 'USD',
amount: 47,
priority: 2,
},
{
id: 30,
method: 1,
currency: 'USD',
amount: 57,
priority: 2,
},
{
id: 7,
method: 5,
currency: 'RUB',
amount: 140,
priority: 1,
},
{
id: 37,
method: 5,
currency: 'RUB',
amount: 22,
priority: 1,
},
{
id: 5,
method: 3,
currency: 'RUB',
amount: 100,
priority: 1,
},
]
Массив может быть сколь угодно большим. Стоит задача выбрать из него только "актуальные" элементы. То есть, нужно сначала сгруппировать элементы по method, currency, priority, а затем в каждой группе забрать только те элементы, у которых amount > 50 + элемент группы, у которого amount < 50, но самый большой в группе. Нужные элементы вынести в отдельный массив.
Иными словами нужно сначала определить элементы с одинаковым методом, валютой и приоритетом и из них забрать только те, у которых сумма больше 50 и элемент с суммой меньше 50, но больше всех остальных в этой группе.
По массиву из примера результат должен быть следующим:
result = [
{
id: 22,
method: 1,
currency: 'RUB',
amount: 100,
priority: 1,
},
{
id: 25,
method: 1,
currency: 'RUB',
amount: 49,
priority: 1,
},
{
id: 33,
method: 1,
currency: 'USD',
amount: 55,
priority: 1,
},
{
id: 30,
method: 1,
currency: 'USD',
amount: 57,
priority: 2,
},
{
id: 77,
method: 1,
currency: 'USD',
amount: 47,
priority: 2,
},
{
id: 7,
method: 5,
currency: 'RUB',
amount: 140,
priority: 1,
},
{
id: 37,
method: 5,
currency: 'RUB',
amount: 22,
priority: 1,
},
{
id: 5,
method: 3,
currency: 'RUB',
amount: 100,
priority: 1,
},
]
Не могу ещё в такую сложную (для меня) группировку элементов массива, прошу помощи. Мне нужен именно алгоритм такой фильтрации. Заранее спасибо!
Ответы (1 шт):
Основная идея - это группировать по единому ключу, который является объединением нужных для группировки св-в и уникальным для каждой группы, остальное элементарно:
- Все у кого
amount > 50автоматом попадают в конечный массив - Далее по одному смотрим не тех у кого
amount <= 50. Если он первый то запоминаем его, если не первый то сравниваем с тем что уже хранится, если у новогоamountбольше чем у сохранённого то делаем замену иначе просто пропускаем
Вот реализация:
const arr = [{
method: 1,
currency: 'RUB',
amount: 10,
priority: 1,
},
{
id: 22,
method: 1,
currency: 'RUB',
amount: 100,
priority: 1,
},
{
id: 25,
method: 1,
currency: 'RUB',
amount: 49,
priority: 1,
},
{
id: 33,
method: 1,
currency: 'USD',
amount: 55,
priority: 1,
},
{
id: 77,
method: 1,
currency: 'USD',
amount: 47,
priority: 2,
},
{
id: 30,
method: 1,
currency: 'USD',
amount: 57,
priority: 2,
},
{
id: 7,
method: 5,
currency: 'RUB',
amount: 140,
priority: 1,
},
{
id: 37,
method: 5,
currency: 'RUB',
amount: 22,
priority: 1,
},
{
id: 5,
method: 3,
currency: 'RUB',
amount: 100,
priority: 1,
},
];
const groups = new Map();
const filteredArr = [];
arr.forEach(item => {
const isAmountBig = item.amount > 50;
if (isAmountBig) {
filteredArr.push(item);
return;
}
const key = `${item.method}-${item.currency}-${item.priority}`;
if (!groups.has(key)) {
groups.set(key, {maxValue: item.amount, item});
return;
}
const group = groups.get(key);
if (item.amount <= group.maxValue) return;
group.maxValue = item.amount;
group.item = item;
});
[...groups.values()].forEach(groupItem => filteredArr.push(groupItem.item));
console.log(filteredArr);
P.S. При желании new Map() можно спокойно заменить обычным объектом, логика не пострадает, только надо будет переписать пару строк