0

I need to convert the following array of objects into a an object format when topic = 'favorites'.

Original Format

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

Converted Format

{
    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'
},

I've been trying to work with the following but I'm a bit off.

events.filter((event) => event.topic === "favorites").map(receiver, datetime => receiver: datetime)
3
  • how do you get the result from given data? Commented Dec 30, 2020 at 10:10
  • Thats what I'm trying to workout... I need to get from the original format to the converted format Commented Dec 30, 2020 at 10:12
  • 1
    The syntax on the map is wrong, it should be { receiver, datetime } Commented Dec 30, 2020 at 10:13

8 Answers 8

2

You could filter and map the entries for a new object.

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

Sign up to request clarification or add additional context in comments.

Comments

2

Your given data doesn't correspond to your expected output by value. But I assume the format is correct. It also seems like, in your result, you want the dates in ISO string form. But in your source object they are kept as a Date object. So I'll be assuming the source array does indeed contain Date objects.

With that said, you really just have to turn every object into [receiver, datetime] (after filtering) and do Object.fromEntries on the result

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

Comments

1

A one line reducer should be sufficient

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" && 
    { ...acc, [val.receiver]: val.datetime } ||
    acc, {}));

2 Comments

I find the expression <condition> && <if true> || <if false> a little bit unintuitive. Using the ternary operator feels more idiomatic: <condition> ? <if true> : <if false>.
It's a matter of usage I suppose: if the code is shared with others, readability may be important. In that case I would actually opt for if (val.topic === "favorites") {...} else {...}. Otherwise boolean short circuit or ternary (in this case) are equivalent.
1

With reduce you can built an object that will be updated in every iteration.

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'
}
*/

Comments

1

you can use reduce and filter for this in combination

I had to do a string out of datetime otherwise it would result in an error.

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

Comments

1

You can use reduce like this:

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'
}
*/

Comments

1

This is a classic use case for using the .reduce() prototype function on the array. This will save you multiple repeated iterations with fewer lines of code.

The example data doesn't seem to match but I am assuming the format is correct.

In your case, you can use reduce like this -

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

To better understand how reduce works - https://www.freecodecamp.org/news/reduce-f47a7da511a9/

Comments

0

A single reduce combined with a topic filter should be enough and some answers have already demonstrated how to do this.

This answer does that but adds:

  1. Currying. So you can apply the transformation to other topics
  2. The comma operator instead of the spread operator. Depending on how big the list to process is, the spread operator can quickly become a performance bottleneck
const transform =
  topic => xs =>
    xs.reduce( (o, x) =>
                  (x.topic === topic
                    ? (o[x.receiver] = x.datetime, o)
                    : o), {});

What's going on here?

The function is curried; it takes a topic then a list to process. This means you can build two topic-processing functions:

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

These two functions now only wait for a list to be processed. Assuming list is the same as your events array:

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"
// }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.