Я написал логику, чтобы объединить все партии из переменной message2
. Он объединит всю партию, если есть дублирующее имя пакета (AA, BB) и вычисляет строки.
var message2 = {
Batches: [
{Batch: "AA", Lines: 1 },
{Batch: "BB", Lines: 2 },
{Batch: "BB", Lines: 6 }
]
}
Становиться:
[ { Batch: 'AA', Lines: 1 }, { Batch: 'BB', Lines: 8 } ]
Это делается методом reduce()
.
В цикле forEach
он mergedBatches
все объединенные mergedBatches
(после объединения) и сравнивается с партией в переменной Worker
. Ему нужно будет найти одно и то же имя пакета, если линия Worker
больше mergedBatches
строкой, а затем устанавливает mergedBatches
в соответствии с линией Worker
.
var message2 = {
Batches: [
{Batch: "AA", Lines: 1 },
{Batch: "BB", Lines: 2 },
{Batch: "BB", Lines: 6 }
]
}
var Worker = {
Batches: [
{Batch: "AA", Lines: 2 },
{Batch: "BB", Lines: 3 },
]
}
var mergedBatches = message2.Batches.reduce((acc, obj)=>{
var existObj = acc.find(b => b.Batch === obj.Batch);
if(existObj) {
existObj.Lines += obj.Lines;
return acc;
}
acc.push({Batch: obj.Batch, Lines: obj.Lines});
return acc;
},[]);
mergedBatches.forEach((b) => {
var workerBatch = Worker.Batches.find(wB => wB.Batch === b.Batch);
if (b.Lines >= workerBatch.Lines) {
b.Lines = workerBatch.Lines;
}
});
console.log(mergedBatches)
Конечный результат, который работает как ожидалось:
[ { Batch: 'AA', Lines: 1 }, { Batch: 'BB', Lines: 3 } ]
Есть ли способ реорганизовать этот код, чтобы сделать его читаемым или лучше?
Вот более короткая версия:
mergedBatches
не должны содержать ссылки на записи message2.Batches
вы можете использовать деструктурирование: acc.push({...cur })
;if/else
должно быть более читаемым без скобок;find
может возвращать undefined.
const message2 = {
Batches: [
{Batch: "AA", Lines: 1 },
{Batch: "BB", Lines: 2 },
{Batch: "BB", Lines: 6 }
]
}
const Worker = {
Batches: [
{Batch: "AA", Lines: 2 },
{Batch: "BB", Lines: 3 },
]
}
const mergedBatches = message2.Batches.reduce((acc, cur) => {
const prev = acc.find(x => x.Batch === cur.Batch)
if (prev) prev.Lines += cur.Lines
else acc.push(cur)
return acc
}, [])
mergedBatches.forEach((mb) => {
const wb = Worker.Batches.find(x => x.Batch === mb.Batch)
if (wb && wb.Lines < mb.Lines ) mb.Lines = wb.Lines
})
console.log(mergedBatches)
Это немного более прямолинейно и должно быть быстрее:
const mergeBatches = (message) => {
const obj = {};
for (let i = message.Batches.length; i--;) {
const current = message.Batches[i];
if (current.Batch in obj) {
obj[current.Batch] += current.Lines;
} else {
obj[current.Batch] = current.Lines;
}
}
const arr = [];
for (let key in obj) {
arr.push({
Batch: key,
Lines: obj[key]
})
}
return arr;
}
Его действительно хорошо, что вы изучаете функциональные шаблоны, но они не всегда самые быстрые.
Например, ваш код имеет acc.find
. Под капотом find
выполняет итерацию по массиву acc
каждый раз, когда выполняется функция, что делает сложность O (n * n). Я думаю, что это так, кто-то комментирует, если я ошибаюсь.
В функции, которую я предоставил, вы выполняете только итерацию по массиву партий, который делает это O (n).
mergeBatches
и Worker
. Посмотрите, if (b.Lines >= workerBatch.Lines) { }
из моей темы.
find
так что трудно сказать.
Из вашей нынешней структуры это будет еще один способ достичь ожидаемого результата:
const merged = {};
message2.Batches.forEach(b => {
if(merged[b.Batch]) {
merged[b.Batch].Lines += b.Lines;
} else {
merged[b.Batch] = b;
}
});
const result = [];
Worker.Batches.forEach(b => {
if (merged[b.Batch] && merged[b.Batch].Lines > b.Lines) {
merged[b.Batch].Lines = b.Lines;
}
result.push(merged[b.Batch]);
});
// Output
[{ "Batch": "AA", "Lines": 1 }, { "Batch": "BB", "Lines": 3 }]