Слияние и сравнение

1

Я написал логику, чтобы объединить все партии из переменной 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 } ]

Есть ли способ реорганизовать этот код, чтобы сделать его читаемым или лучше?

  • 0
    Это довольно просто с библиотекой типа underscore / lodash. Вы используете один из них?
  • 2
    @tokland Я не хочу использовать какую-либо библиотеку.
Показать ещё 8 комментариев
Теги:

3 ответа

0
Лучший ответ

Вот более короткая версия:

  1. если mergedBatches не должны содержать ссылки на записи message2.Batches вы можете использовать деструктурирование: acc.push({...cur });
  2. однострочное if/else должно быть более читаемым без скобок;
  3. null-check в последнем состоянии: 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)
0

Это немного более прямолинейно и должно быть быстрее:

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

  • 0
    Спасибо. Отсутствует логика для проверки количества строк между переменными mergeBatches и Worker . Посмотрите, if (b.Lines >= workerBatch.Lines) { } из моей темы.
  • 0
    Вопрос сводится к тому, насколько велик набор данных. В этом случае возможно, что оригинал будет работать быстрее, чем ваш обновленный код, даже с использованием команды find так что трудно сказать.
Показать ещё 2 комментария
0

Из вашей нынешней структуры это будет еще один способ достичь ожидаемого результата:

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 }]

Ещё вопросы

Сообщество Overcoder
Наверх
Меню