Сократить массив объектов на основе пользовательской логики - PullRequest
0 голосов
/ 29 марта 2020

Я пытаюсь уменьшить массив объектов путем объединения ключей между ними на основе логики c.

Объяснение

Я бы хотел уменьшить следующие массивы (см. Ниже) по их ключам:

  1. lines: объединить диапазоны чисел, которые являются общими между ними (например: [1,2] + [3,2] = [1,2,3])
  2. dates: объединяет даты массивов, связанные с lines ключи

Все дублирующие массивы и / или ключи должны быть удалены.

Примеры:

Ввод пример A :

const errors = [
  {
    "lines": [1, 2],
    "dates": [["2020-12-12","2020-12-19"], ["2020-12-13","2020-12-25"]]
  },
  {
    "lines": [1, 3],
    "dates": [["2020-12-12","2020-12-19"], ["2020-12-15","2020-12-17"]]
  },
  {
    "lines": [2, 3],
    "dates": [["2020-12-13","2020-12-25"], ["2020-12-15","2020-12-17"]]
  },
  {
    "lines": [3, 2],
    "dates": [["2020-12-15","2020-12-17"], ["2020-12-13","2020-12-25"]]
  }
]

Выход пример A :

const expected = [{
  lines: [1, 2, 3],
  dates: [
    ["2020-12-12", "2020-12-19"],
    ["2020-12-13", "2020-12-25"],
    ["2020-12-05", "2020-12-20"],
    ["2020-12-15", "2020-12-17"]
  ]
}];

Вход пример B :

const errors = [
  {
    lines: [1, 2],
    dates: [["2020-12-12", "2020-12-19"], ["2020-12-04", "2020-12-25"]]
  },
  {
    lines: [1, 5],
    dates: [["2020-12-12", "2020-12-19"], ["2020-12-05", "2020-12-20"]]
  },
  {
    lines: [2, 5],
    dates: [["2020-12-04", "2020-12-25"], ["2020-12-05", "2020-12-20"]]
  },
  {
    lines: [3, 4],
    dates: [["2020-10-19", "2020-10-25"], ["2020-10-24", "2020-10-27"]]
  },
  {
    lines: [4, 3],
    dates: [["2020-10-24", "2020-10-27"], ["2020-10-19", "2020-10-25"]]
  },
  {
    lines: [5, 2],
    dates: [["2020-12-05", "2020-12-20"], ["2020-12-04", "2020-12-25"]]
  }
];

Вывод пример B :

const expected = [
  {
    lines: [1, 2, 5],
    dates: [
      ["2020-12-12", "2020-12-19"],
      ["2020-12-04", "2020-12-25"],
      ["2020-12-05", "2020-12-20"]
    ]
  },
  {
    lines: [3, 4],
    dates: [
      ["2020-10-19", "2020-10-25"],
      ["2020-10-24", "2020-10-27"]
  ]
  }
];

Я создал песочницу для достижения этой цели: https://codesandbox.io/s/lodash-sandbox-zsr9r

Есть три примера, третий не работает.

Моя текущая реализация:

const sanatizeErrors = errors.reduce((acc, currentError, i) => {
  const nextError = errors[i + 1]
  const hasOnlySingleError = errors.length === 1

  // The following const is not enough "strong" and it doesn't handle all cases
  const hasCommonErrorWithNextLine =
    nextError && _.includes(nextError.lines, currentError.lines[0])

  if (hasOnlySingleError) {
    return [{
      lines: currentError.lines,
      dates: currentError.dates
    }]
  }

  if (hasCommonErrorWithNextLine) {
    return [
      ...acc,
      {
        lines: _.uniq([
          ...currentError.lines,
          ...nextError.lines
        ]),
        dates: _.uniqWith(
          [
            ...currentError.dates,
            ...nextError.dates
        ], _.isEqual)
      }
    ]
  }

  return acc
}, [])

Этот последний массив используется для обработки динамических перекрытий диапазонов дат c.

Любой основной момент ценится =)

1 Ответ

1 голос
/ 01 апреля 2020

Как только условия становятся достаточно сложными, а структура данных также сложной - код довольно запутанный. Будем рады проверить другие идеи. Я добавил комментарии во фрагмент, чтобы объяснить логику c. Если у вас есть какие-либо вопросы - добро пожаловать

const errors = [
  {
    lines: [1, 2],
    dates: [["2020-12-12", "2020-12-19"], ["2020-12-04", "2020-12-25"]]
  },
  {
    lines: [1, 5],
    dates: [["2020-12-12", "2020-12-19"], ["2020-12-05", "2020-12-20"]]
  },
  {
    lines: [2, 5],
    dates: [["2020-12-04", "2020-12-25"], ["2020-12-05", "2020-12-20"]]
  },
  {
    lines: [3, 4],
    dates: [["2020-10-19", "2020-10-25"], ["2020-10-24", "2020-10-27"]]
  },
  {
    lines: [4, 3],
    dates: [["2020-10-24", "2020-10-27"], ["2020-10-19", "2020-10-25"]]
  },
  {
    lines: [5, 2],
    dates: [["2020-12-05", "2020-12-20"], ["2020-12-04", "2020-12-25"]]
  }
];

let output = errors.reduce((acc,rec) => {
  let i;
  //iterate through elements of accumulator to check where to merge
for (i = 0; i < acc.length; i++) {    
  let current = acc[i]
  // if there are duplicates
  if(current.lines.map(it => rec.lines.indexOf(it) > -1).some(it => it))
    {
      // combine and merge (remove duplicates) arrays of lines   
      acc[i].lines = (acc[i].lines.concat(rec.lines)).filter((it, i, arr) => arr.indexOf(it) === i)
      // combine and merge (remove duplicates) arrays of dates. In filter complex check to find lastPosition of elements. IndexOf wont't work when arrays are compared (as works for lines)
      acc[i].dates = (acc[i].dates.concat(rec.dates)).filter((it, i, arr) => {
  const lastPosition = arr.reduce((acc,rec, idx) => rec[0] === it[0] && rec[1] === it[1] ? idx: acc, 0)
  return i === lastPosition
})
    // if place for merge has been found - finish
    return acc
  }  
  }
    // if there is no place for merge  - add new group
   return [...acc, rec]
  
  },[])


    console.log('result', output);
...