Разделенный массив с условием на элементе

#javascript #arrays #filter

Вопрос:

Итак, у меня есть массив, который выглядит так:

 [
  { date: '2021-07-07' },
  { date: '2021-07-07' },
  { date: '2021-07-07' },
  { date: '2021-07-08' },
  { date: '2021-07-09' },
  { date: '2021-07-10' },
  { date: '2021-07-10' }
];
 

Как я могу разделить массив на 3 (я имею в виду 1 группу для уникальных дат и другую группу для дубликатов, но если их более 1, она должна разделиться на другую группу)

Это будет выглядеть так после разделения

 Array 1
[{"date": "2021-07-07"},{"date": "2021-07-07"},{"date": "2021-07-07"}]
Array 2
[{"date": "2021-07-08"},{"date": "2021-07-09"}]
Array 3
[{"date": "2021-07-10"},{"date": "2021-07-10"}]
 

Ниже приведен мой код до сих пор, но он работает только в том случае, если дубликат на 1

 const findDuplicates = arr => {
  let sorted_arr = arr.slice().sort();
  let result = [];
  for (let i = 0; i < sorted_arr.length - 1; i  ) {
    if (sorted_arr[i   1].date == sorted_arr[i].date) {
      result.push(sorted_arr[i]);
    }
  }
  return resu<
};

const filterSame = arr => {
  let temp = findDuplicates(arr);
  const result = arr.filter(date => date.date == temp[0].date);
  return resu<
};

const filterUnique = array => {
  let result = array.filter(
    (e, i) => array.findIndex(a => a['date'] === e['date']) === i
  );
  let temp = findDuplicates(array);
  result = result.filter(function(obj) {
    return obj.date !== temp[0].date;
  });
  return resu<
};
 

Комментарии:

1. Почему 2021-07-08 и 2021-07-09 сгруппированы вместе?

2. @adiga, потому что это больше, чем просто простая группировка. Это группировка, за которой следует объединение всего с помощью только 1 элемента.

3. Я понял это как сгруппировать все элементы по дате, где есть дубликаты, но затем создать другую группу для всех уникальных дат. Это в основном основано на ожидаемом результате TBH

4. @Jamiec уникальные переходят в группу, а дубликаты-в отдельные группы?

5. вот как я понял вопрос «да». Это не особенно хорошо описано, но в этом, безусловно, есть нечто большее, чем простая группа, созданная в соответствии с обманом

Ответ №1:

Вы можете создать карту с указанием дат и значением в качестве пустого массива. Затем заполните эти массивы. Наконец, извлеките массивы, содержащие более одного элемента, и добавьте к этому результату объединенный массив из этих одноэлементных массивов:

 function group(data) {
    let map = new Map(data.map(o => [o.date, []]));
    for (let o of data) map.get(o.date).push(o);
    return [
        ...[...map.values()].filter(({length}) => length > 1),
        [...map.values()].filter(({length}) => length == 1).flat()
    ];
}

let data = [{"date":"2021-07-07"},{"date":"2021-07-07"},{"date":"2021-07-07"},{"date":"2021-07-08"},{"date":"2021-07-09"},{"date":"2021-07-10"},{"date":"2021-07-10"}];

console.log(group(data)); 

Объяснение

 let map = new Map(data.map(o => [o.date, []]));
 

Это создает карту. Конструктору дается массив пар. Для примера данных этот массив выглядит следующим образом:

 [
   ["2021-07-07", []],
   ["2021-07-07", []],
   ["2021-07-07", []],
   ["2021-07-08", []],
   ["2021-07-09", []],
   ["2021-07-10", []],
   ["2021-07-10", []]
]
 

Конструктор карт создаст соответствующую карту, которая действительно удаляет дубликаты. Вы можете представить это следующим образом (хотя это не простой объект).:

 {
    "2021-07-07": [],
    "2021-07-08": [],
    "2021-07-09": [],
    "2021-07-10": []
}
 

Затем for цикл заполнит эти (четыре) массива, так что карта будет выглядеть следующим образом:

 {
    "2021-07-07": [{date:"2021-07-07"},{date:"2021-07-07"},{date:"2021-07-07"}],
    "2021-07-08": [{date:"2021-07-08"}],
    "2021-07-09": [{date:"2021-07-09"}],
    "2021-07-10": [{date:"2021-07-10"},{date:"2021-07-10"}]
}
 

В return инструкции значения карты дважды преобразуются в массив. Один раз для фильтрации записей, содержащих более 1 элемента:

 [
    [{date:"2021-07-07"},{date:"2021-07-07"},{date:"2021-07-07"}],
    [{date:"2021-07-10"},{date:"2021-07-10"}]
]
 

…и второй раз, чтобы получить те, у которых есть 1 элемент:

 [
    [{date:"2021-07-08"}],
    [{date:"2021-07-09"}],
]
 

Второй массив сплющен с flat() :

 [
    {date:"2021-07-08"},
    {date:"2021-07-09"},
]
 

Конечный результат объединяет первый массив (с повторяющимися датами) с уплощенным массивом (с уникальными датами), используя синтаксис распространения ( ... )

Комментарии:

1. Я так предпочитаю этот ответ своему собственному. Мило!

2. это работает, это очень хорошо, если вы оставите какой-нибудь комментарий, чтобы я мог знать, что происходит, но в любом случае спасибо.

3. Добавил объяснение к моему ответу. Надеюсь, это прояснит ситуацию.

4. Этот ввод имеет вложенную структуру (массив массивов объектов), в то время как ваш вопрос содержит массив объектов. Поэтому в этом случае вы должны сначала применить .flat() свои входные данные, прежде чем передавать их функции в моем ответе. Конечно, важно, чтобы ваш ввод имел последовательную форму .

5. Реализовали ли вы призыв к .flat() тому, что у меня есть в моем ответе (я добавил его немного после публикации первоначального ответа)?

Ответ №2:

Это можно было бы сделать в 2 этапа

  1. типичная группировка по операциям на основе date свойств
  2. объединение всех групп, которые имеют только 1 результат.
 const input = [{"date":"2021-07-07"},{"date":"2021-07-07"},{"date":"2021-07-07"},{"date":"2021-07-08"},{"date":"2021-07-09"},{"date":"2021-07-10"},{"date":"2021-07-10"}]

const grouped = input.reduce ( (acc,i) => {
    if(!acc[i.date]) acc[i.date] = []
    acc[i.date].push(i);
    return acc;
},{});

const final = Object.values(Object.entries(grouped).reduce( (acc,[key,values]) => {
   if(values.length>1) {
       acc[key] = values;
   }
   else{
      if(!acc.others) acc.others = [];
      acc.others.push(values[0]);
   }
   return acc
},{}))

console.log(final); 

Обратите внимание, что если вы добавите, например, 2021-07-11 в свой исходный массив, это будет объединено со всеми другими «уникальными» элементами. Это может быть или не быть тем, чего вы ожидали, но не было ясно из вопроса.

Ответ №3:

Другой вариант-обратиться к sort массиву перед группировкой. Если date зацикливаемый ток не совпадает со своими соседями, то у него нет дубликатов.

 const input = [{"date":"2021-07-07"},{"date":"2021-07-07"},{"date":"2021-07-07"},{"date":"2021-07-08"},{"date":"2021-07-09"},{"date":"2021-07-10"},{"date":"2021-07-10"}]

input.sort((a,b) => a.date.localeCompare(b.date))

const grouped = input.reduce((acc, o, i, arr) => {
  const key = o.date === arr[i-1]?.date || o.date === arr[i 1]?.date
                ? o.date
                : 'lonely'
                
  acc[key] ||= []
  acc[key].push(o);
  return acc;
}, {});

console.log(Object.values(grouped));