Guide to generating a fresh array of objects by combining values from two arrays!

I'm having difficulties combining two arrays of objects (retrieved from blockchain data) into a new array based on the values of the objects.

The aim is to extract the most recent interaction with a user.

A simplified yet closely resembling representation of the data structure where this issue arises:

interface MsgSlice {
    messageId: string;
    messageDataSlice: {
        senderId?: string;
        receiverId: string;
        timestamp: number;
    };
};

const latestReceivedMsgs: MsgSlice[] = [
    {
        messageId: "messageId1",
        messageDataSlice: {
            senderId: "userId1",
            receiverId: "ownerId", // <- always same in that array
            timestamp: 101,
        },
    },
    {
        messageId: "messageId3",
        messageDataSlice: {
            senderId: "userId2",
            receiverId: "ownerId",
            timestamp: 103,
        },
    },
    {
        messageId: "messageId5",
        messageDataSlice: {
            senderId: "userId3",
            receiverId: "ownerId",
            timestamp: 105,
        },
    },
];

const latestSentMsgs: MsgSlice[] = [
    {
        messageId: "messageId2",
        messageDataSlice: {
            // senderId: "ownerId",
            receiverId: "userId1",
            timestamp: 102,
        },
    },
    {
        messageId: "messageId4",
        messageDataSlice: {
            receiverId: "userId3",
            timestamp: 104,
        },
    },
];

The expected outcome should include the newest messageId either 'sent to' or 'received by' the respective user. Something like this:


const latestInteraction = [
    {
        user: "userId1",
        messageId: "messageId2",
        timestamp: 102,
    },
    {
        user: "userId2",
        messageId: "messageId3",
        timestamp: 103,
    },
    {
        user: "userId3",
        messageId: "messageId5",
        timestamp: 105,
    },
]   

To address this, my initial approach was to iterate over the arrays and within each iteration, also go through the other array to compare the senderId and receiverId values. If "senderId is == one of the iterated receiverIds", it could be included in an interaction array, which can then be sorted chronologically and filtered. However, I struggled to make this method work effectively. Perhaps my thinking is constrained here, and there are likely more efficient methods to achieve this task than what I initially proposed.

Answer №1

One effective method is to utilize the hash grouping technique with a pure JavaScript solution

Check out the Live Demo below:

const latestReceivedMsgs = [{messageId: "messageId1",messageDataSlice: {senderId: "userId1",receiverId: "ownerId", timestamp: 101,},},{messageId: "messageId3",messageDataSlice: {senderId: "userId2",receiverId: "ownerId",timestamp: 103,},},{messageId: "messageId5",messageDataSlice: {senderId: "userId3",receiverId: "ownerId",timestamp: 105,},},];
const latestSentMsgs = [{messageId: "messageId2",messageDataSlice: {receiverId: "userId1",timestamp: 102,},},{messageId: "messageId4",messageDataSlice: {receiverId: "userId3",timestamp: 104,},},];

const grouped = [...latestReceivedMsgs, ...latestSentMsgs]
  .reduce((acc, { messageId, messageDataSlice }) => {
    const { timestamp, senderId, receiverId } = messageDataSlice;
    const user = senderId ?? receiverId;
    const msgItem = { user, messageId, timestamp };
    if ((acc[user]?.timestamp ?? 0) < timestamp) acc[user] = msgItem;
    
    return acc;
  }, {});

const result = Object.values(grouped);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0 }

UPDATE

You can also explore the TypeScript option:

interface MsgSlice {
  messageId: string;
  messageDataSlice: {
    senderId?: string;
    receiverId?: string;
    timestamp: number;
  };
};

interface Interaction {
  user: string
  messageId: string
  timestamp: number
};

const latestReceivedMsgs: MsgSlice[] = [{messageId: "messageId1",messageDataSlice: {senderId: "userId1",receiverId: "ownerId", // <- always same in that array},},{messageId: "messageId3",messageDataSlice: {senderId: "userId2",receiverId: "ownerId",timestamp: 103,},},{messageId: "messageId5",messageDataSlice: {senderId: "userId3",receiverId: "ownerId",timestamp: 105,},},];
const latestSentMsgs: MsgSlice[] = [{messageId: "messageId2",messageDataSlice: {receiverId: "userId1",timestamp: 102,},},{messageId: "messageId4",messageDataSlice: {receiverId: "userId3",timestamp: 104,},},];

const grouped = ([...latestReceivedMsgs, ...latestSentMsgs] as MsgSlice[])
  .reduce((acc, { messageId, messageDataSlice }) => {
    const { timestamp, senderId, receiverId } = messageDataSlice;
    const user = senderId ?? receiverId ?? "unindefined";
    const msgItem = { user, messageId, timestamp };
    if ((acc[user]?.timestamp ?? 0) < timestamp) acc[user] = msgItem
    
    return acc;
  }, {} as { [key: Interaction['user']]: Interaction });

const result: Interaction[] = Object.values(grouped);

console.log(result);

Answer №2

To streamline the process, I would suggest merging your incoming and outgoing messages into a unified array of "interactions" that holds only relevant information. When handling a received message, focus on the senderId, whereas for a sent message, concentrate on the receiverId (ensuring you capture the other user involved in each interaction). You can structure it like this:

interface Interaction {
  user: string
  messageId: string
  timestamp: number
}

function latestInteractions(
  receivedMsgs: MsgSlice[], 
  sentMsgs: MsgSlice[]
): Interaction[] {

// Code implementation goes here

}

In order to extract the necessary data efficiently, we create an object named interactionMap where each unique user corresponds to the most recent Interaction. This ensures that we maintain one interaction per user with the highest timestamp:

// Further code implementation

By utilizing the Object.values() method, we can convert the object holding interactions into an array format:

// Additional code implementation 

The resulting array will contain all pertinent details, aiding in straightforward analysis or manipulation based on specific requirements. Should you wish to customize the order of elements, sorting functions can be applied accordingly.


Test the functionality using your test scenario:

// Test case execution

Seems to be working well!

Link to code Playground for testing

Answer №3

To combine both arrays and arrange them in chronological order based on timestamp, you can flatten the arrays and then use the sort method as shown below:

const allMessages: MessageBlock[] = [];
allMessages.push(...receivedMessages);
allMessages.push(...sentMessages);

allMessages.sort((x, y) => {
    return x.timestamp - y.timestamp;
});

Answer №4

One approach could be combining the messages into a single array and then arranging them in chronological order based on their timestamps.

const allMessages = [...receivedMessages, ...sentMessages];
allMessages.sort((a,b) => a.timestamp - b.timestamp);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Adding a fixed list as a separate column in a PySpark dataframe

Here is a sample list of items: my_list = ['x', 'y', 'z'] I have a dataframe that already exists and I wish to add my_list as a new column in the existing dataframe. For instance, this is the input dataframe: from pyspark.sq ...

Identifying the largest and smallest variance between the first and second elements within a 2D array

I created a function that accepts a list of 2D elements (lists with 2 elements each) as an input and returns the element(s) with the largest difference between their elements and the one(s) with the smallest difference. For example, if the input is ([2,8], ...

Checking the status of a checkbox after submitting using AngularJs

For my first application, I am utilizing AngularJs and JavaScript to display information from an API as checkboxes. Currently, the functionality is working well, but I am unsure how to validate if any checkbox options are checked with a submit button. Aft ...

The predicament encountered with user registration in the realm of Node.js

I am encountering a problem with the sign-up route in node.js and MongoDB. Whenever I attempt to post data using Insomnia, it displays an error message. You can find the screenshot of the error [here](https://i.stack.imgur.com/qnGAv.png). Here is the code ...

"Why does the useEffect in Next.js fire each time I navigate to a new route

Currently, I have implemented a useEffect function within the Layout component. This function is responsible for fetching my userData and storing it in the redux-store. However, I have noticed that this function gets triggered every time there is a route c ...

Querying arrays in Mongoose

I'm facing a challenge with querying my database to extract a specific array element from within a user model. The schema is structured as follows: const schemaUser = new mongoose.Schema({ username: { type: String, required: true, unique: true }, ...

Dynamically load a vuejs library and display the component within it

I've set up a Vue.js app to act as a container for multiple other "apps". The goal was to: have a reusable codebase for discovering/loading components develop the other apps as Vue.js libraries to allow component loading In my first library, I have ...

The functionality of AngularJS ng-model seems to be disrupted when it is set within a directive

Is it possible to automatically generate the ng-model of an input based on the name of the input itself? This requirement arises from using Html.TextBoxFor in MVC, which creates the necessary name for binding the input to the server-side model. To streamli ...

How to extract data from JSON files using Angular 12

Having trouble with Angular and TypeScript. Need to fetch a GET API from Spring where the return variable is Page, but the JSON structure looks like this: "content": [ { "id": 1, "category": "TSHIRT&qu ...

Want to know how to choose a class or id when a button is clicked using jQuery?

One particular div containing a class of "vote" holds: <div class="vote"> <input type="hidden" name="q_id" class="q_id" id="q_id" q_id="{{ result.object.id }}" value="{{ result.object.id }}"> <button type="submit" class="downvote" value="do ...

Issue: Module XXX not found (TypeScript aliases)

Encountered a perplexing issue that I can't seem to solve. I am in the process of creating an NPM package to serve as a backend API for another project. Utilizing TypeScript and Node.js for development. My objective is to modify my import statements ...

Is it possible to interpret this in TypeScript?

I need assistance in understanding the following Code snippet. Can someone guide me through it? [Symbol.iterator](): IterableIterator<IPv4> { return this; } ...

Angular ng-repeat is incompatible with the JSON parser

I am facing an issue with accessing JSON objects and setting values into Angular Ui-grid. The problem arises when some of the fields in my JSON object are actually JSON strings. I attempted to convert these fields into JSON objects using JSON.parser, but e ...

React: Import default export as a string

Help needed with JSON data import import dataOption1 from './Option1.json' import dataOption2 from './Option2.json' async setParamsByDomain(optionUser) { await this.setState({ jsonName: "data"+ optionUser}); console.log(t ...

How can we initiate the AJAX request right away while also making sure the page is fully loaded before adding

One trick I've discovered is that by submitting an AJAX request in the <head> section of my webpage, I can avoid a minor flicker on page load when loading content via AJAX. Of course, this method still needs some refining to handle longer AJAX r ...

No matter how hard I try, the async function within the React Component keeps returning 'Promise {<pending>}' consistently

Currently, I'm facing an issue where running an asynchronous function inside a functional component in React (NextJS) results in the function returning a pending promise: Promise {<pending>}. Oddly enough, fetching data from a dummy API works pe ...

The API response appears to be a successful 200 status code, however the actual result is a

I'm currently working with a VUEJS / VUEJS Resources code snippet that retrieves data from an API service. fetchData: function(name){ var self = this; self.$http.get('http://www.apiservice.com/', { params: { ...

I am currently using React to implement a feature that displays random facts for 5-second intervals. Despite no errors being displayed, the facts are not appearing on the page as expected

Client side My react application includes a section that is supposed to display random facts at 5-second intervals. Although no errors are displayed, the facts do not appear on the page when I run the code. import React from "react"; import &quo ...

Optimizing jQuery Dialog for Different Window Sizes

I am currently developing a responsive website and facing a challenge. I need to implement a popup for window sizes smaller than 480px, but on desktop screens, the content should be visible without being inside the popup. I want to avoid duplicating the co ...

Jquery button click event is malfunctioning after the inclusion of jquery keyboard plugin

When I try to gather user input from a textbox using jQuery keyboard.js, the functionality works perfectly fine if I exclude the virtual keyboard code. For more information on keyboard.js, you can visit: https://github.com/Mottie/Keyboard/wiki Below is t ...