Как отфильтровать массив объектов и объединить их в один объект?

#javascript

#javascript

Вопрос:

Мне нужно преобразовать следующий массив объектов в формат объекта, когда topic = ‘избранное’.

Исходный формат

 const events = [
      {
        topic: 'favorites',
        receiver: '1000066928',
        datetime: 2016-11-26T21:43:54.000Z
      },
      {
        topic: 'favorites',
        receiver: '1000061499',
        datetime: 2017-01-03T19:15:04.000Z
      },
      {
        topic: 'blocked',
        receiver: '1000102733',
        datetime: 2017-01-05T17:04:15.000Z
      },
      {
        topic: 'blocked',
        receiver: '1000107928',
        datetime: 2017-01-06T17:17:05.000Z
      }
    ]
 

Преобразованный формат

 {
    1000000002: '2020-01-24T20:46:05 11:00',
    1000000008: '2020-01-24T20:46:05 11:00',
    1000000009: '2020-01-24T20:46:05 11:00',
    1000000010: '2020-01-24T20:46:05 11:00'
},
 

Я пытался работать со следующим, но у меня немного не получается.

 events.filter((event) => event.topic === "favorites").map(receiver, datetime => receiver: datetime)
 

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

1. как вы получаете результат из заданных данных?

2. Это то, что я пытаюсь тренировать… Мне нужно перейти от исходного формата к преобразованному формату

3. Синтаксис на map неправильный, он должен быть { receiver, datetime }

Ответ №1:

Вы можете отфильтровать и сопоставить записи для нового объекта.

 const
    events = [{ topic: 'favorites', receiver: '1000066928', datetime: '2016-11-26T21:43:54.000Z' }, { topic: 'favorites', receiver: '1000061499', datetime: '2017-01-03T19:15:04.000Z' }, { topic: 'blocked', receiver: '1000102733', datetime: '2017-01-05T17:04:15.000Z' }, { topic: 'blocked', receiver: '1000107928', datetime: '2017-01-06T17:17:05.000Z' }],
    result = Object.fromEntries(events
        .filter(({ topic }) => topic === 'favorites')
        .map(({ receiver, datetime }) => [receiver, datetime])
    );

console.log(result); 

Ответ №2:

Предоставленные вами данные не соответствуют ожидаемому результату по значению. Но я предполагаю, что формат правильный. Также кажется, что в вашем результате вам нужны даты в форме строки ISO. Но в вашем исходном объекте они хранятся как Date объект. Поэтому я предполагаю, что исходный массив действительно содержит Date объекты.

С учетом сказанного, вам действительно просто нужно превратить каждый объект в [receiver, datetime] (после фильтрации) и сделать Object.fromEntries с результатом

 const result = Object.fromEntries(
    events
        .filter(event => event.topic === 'favorites')
        .map(({ receiver, datetime }) => [receiver, datetime.toISOString()])
);
 
 const events = [
    {
        topic: 'favorites',
        receiver: '1000066928',
        datetime: new Date('2016-11-26T21:43:54.000Z'),
    },
    {
        topic: 'favorites',
        receiver: '1000061499',
        datetime: new Date('2017-01-03T19:15:04.000Z'),
    },
    {
        topic: 'blocked',
        receiver: '1000102733',
        datetime: new Date('2017-01-05T17:04:15.000Z'),
    },
    {
        topic: 'blocked',
        receiver: '1000107928',
        datetime: new Date('2017-01-06T17:17:05.000Z'),
    },
];

const result = Object.fromEntries(
    events
        .filter(event => event.topic === 'favorites')
        .map(({ receiver, datetime }) => [receiver, datetime.toISOString()])
);

console.log(result); 

Ответ №3:

Должно быть достаточно однострочного редуктора

 const events = [{
    topic: 'favorites',
    receiver: '1000066928',
    datetime: "2016-11-26T21:43:54.000Z"
  },
  {
    topic: 'favorites',
    receiver: '1000061499',
    datetime: "2017-01-03T19:15:04.000Z"
  },
  {
    topic: 'blocked',
    receiver: '1000102733',
    datetime: "2017-01-05T17:04:15.000Z"
  },
  {
    topic: 'blocked',
    receiver: '1000107928',
    datetime: "2017-01-06T17:17:05.000Z"
  }
]

console.log(events
  .reduce((acc, val) => val.topic === "favorites" amp;amp; 
    { ...acc, [val.receiver]: val.datetime } ||
    acc, {})); 

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

1. Я нахожу это выражение <condition> amp;amp; <if true> || <if false> немного неинтуитивным. Использование троичного оператора кажется более идиоматичным : <condition> ? <if true> : <if false> .

2. Я полагаю, это вопрос использования: если код доступен другим пользователям, читаемость может быть важна. В этом случае я бы действительно выбрал if (val.topic === "favorites") {...} else {...} . В противном случае логическое короткое замыкание или троичное (в данном случае) эквивалентны.

Ответ №4:

С reduce помощью вы можете создать объект, который будет обновляться на каждой итерации.

 const output = events
  .filter((event) => event.topic === "favorites")
  .reduce((acc, cur) => {
    return {...acc, [cur.receiver]: cur.datetime };
  }, {});
console.log(output);
/* {
  '1000061499': '2017-01-03T19:15:04.000Z',
  '1000066928': '2016-11-26T21:43:54.000Z'
}
*/
 

Ответ №5:

вы можете использовать reduce и filter для этого в комбинации

Мне пришлось сделать строку из datetime, иначе это привело бы к ошибке.

 const events = [
      {
        topic: 'favorites',
        receiver: '1000066928',
        datetime: "2016-11-26T21:43:54.000Z"
      },
      {
        topic: 'favorites',
        receiver: '1000061499',
        datetime: "2017-01-03T19:15:04.000Z"
      },
      {
        topic: 'blocked',
        receiver: '1000102733',
        datetime: "2017-01-05T17:04:15.000Z"
      },
      {
        topic: 'blocked',
        receiver: '1000107928',
        datetime: "2017-01-06T17:17:05.000Z"
      }
    ]

const result = events
  .filter((event) => event.topic === "favorites")
  .reduce((accum, element) => {
    return {...accum, [element.receiver]: element.datetime };
  }, {});
console.log(result); 

Ответ №6:

Вы можете использовать reduce так:

 const filteredEvents = events.reduce((a, b) => {
  return b.topic === 'favorites' 
    ? {...a, [b.receiver] : b.datetime} 
    : a
}, {})

console.log(filteredEvents);

/*
{
  '1000061499': '2017-01-03T19:15:04.000Z',
  '1000066928': '2016-11-26T21:43:54.000Z'
}
*/
 

Ответ №7:

Это классический вариант использования функции .reduce() прототипа для массива. Это сэкономит вам несколько повторяющихся итераций с меньшим количеством строк кода.

Данные примера, похоже, не совпадают, но я предполагаю, что формат правильный.

В вашем случае вы можете использовать reduce так —

 const events = [
    {
        topic: 'favorites',
        receiver: '1000066928',
        datetime: new Date('2016-11-26T21:43:54.000Z'),
    },
    {
        topic: 'favorites',
        receiver: '1000061499',
        datetime: new Date('2017-01-03T19:15:04.000Z'),
    },
    {
        topic: 'blocked',
        receiver: '1000102733',
        datetime: new Date('2017-01-05T17:04:15.000Z'),
    },
    {
        topic: 'blocked',
        receiver: '1000107928',
        datetime: new Date('2017-01-06T17:17:05.000Z'),
    },
];

const result = events.reduce((acc, event) => {
  if (b.topic === 'favorites') {
    return {...acc, [event.receiver] : b.datetime};
  }
  return acc;
}, {})

console.log(result);
 

Чтобы лучше понять, как работает reduce — https://www.freecodecamp.org/news/reduce-f47a7da511a9 /

Ответ №8:

Одного сокращения в сочетании с фильтром темы должно быть достаточно, и некоторые ответы уже продемонстрировали, как это сделать.

Этот ответ делает это, но добавляет:

  1. Каррирование. Таким образом, вы можете применить преобразование к другим темам
  2. Оператор запятой вместо оператора распространения. В зависимости от размера обрабатываемого списка оператор spread может быстро стать узким местом в производительности
 const transform =
  topic => xs =>
    xs.reduce( (o, x) =>
                  (x.topic === topic
                    ? (o[x.receiver] = x.datetime, o)
                    : o), {});
 

Что здесь происходит?

Функция обработана; для обработки требуется тема, а затем список. Это означает, что вы можете создать две функции обработки тем:

 const favorites = transform('favorites');
const blocked = transform('blocked');
 

Эти две функции теперь ожидают только обработки списка. Предполагается list , что это то же самое, что и ваш events массив:

 favorites(list);
// { 1000061499: "2017-01-03T19:15:04.000Z"
// , 1000066928: "2016-11-26T21:43:54.000Z"
// }

blocked(list);
// { 1000102733: "2017-01-05T17:04:15.000Z"
// , 1000107928: "2017-01-06T17:17:05.000Z"
// }