Analyzing the similarities in properties between two arrays of objects in order to generate a pair of fresh arrays

I have two sets of data represented as arrays:

var oldOrder = [{"Id": "10","Qty": 1}, {"Id": "3","Qty": 2}, {"Id": "9","Qty": 2}]; 
var newOrder = [{"Id": "5","Qty": 2},{"Id": "10","Qty": 3}, {"Id": "9","Qty": 1}];

I want to merge these arrays into a new one, keeping only one object per Id. If an Id exists in both oldOrder and newOrder, I need to calculate the difference in Qty. For example, combining the above arrays would result in:

var newArray = [{"Id": "5","Qty": 2},{"Id": "10","Qty": 2}, {"Id": "9","Qty": -1}];

Additionally, I want to identify any dropped orders that are in oldOrder but not in newOrder:

var droppedOrders = [{"Id": "3","Qty": 2}];

I have a function to find dropped orders, but I need help incorporating the logic to create the newArray within the same function if possible:

function comparer(otherArray){
  return function(current){
    var onlyInOld = otherArray.filter(function(other){
      return other.Id == current.Id;
    }).length == 0;
    return onlyInOld;
  }
}

var droppedOrders= oldOrder.filter(comparer(newOrder));
console.log(droppedOrders);

It's worth noting that I am unable to use ES6 features like spread or fat arrow functions.

Answer №1

One simple way to achieve the desired outcome is by utilizing the Map feature.

1) Utilizing ES6

var oldOrder = [
  { Id: "10", Qty: 1 },
  { Id: "3", Qty: 2 },
  { Id: "9", Qty: 2 },
];
var newOrder = [
  { Id: "5", Qty: 2 },
  { Id: "10", Qty: 3 },
  { Id: "9", Qty: 1 },
];

const oldMap = new Map(oldOrder.map((o) => [o.Id, o]));
const newMap = new Map(newOrder.map((o) => [o.Id, o]));

const result = newOrder.map((o) =>
  oldMap.has(o.Id) ? { ...o, Qty: o.Qty - oldMap.get(o.Id).Qty } : o
);

const droppedOrders = oldOrder.filter(({ Id }) => !newMap.has(Id));

console.log(result);
console.log(droppedOrders);
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */

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

2) Utilizing ES5

var oldOrder = [
  { Id: "10", Qty: 1 },
  { Id: "3", Qty: 2 },
  { Id: "9", Qty: 2 },
];
var newOrder = [
  { Id: "5", Qty: 2 },
  { Id: "10", Qty: 3 },
  { Id: "9", Qty: 1 },
];

const oldMap = {};
const newMap = {};
oldOrder.forEach(function (o) {
  oldMap[o.Id] = o;
});
newOrder.forEach(function (o) {
  newMap[o.Id] = o;
});

const result = newOrder.map(function (o) {
  return oldMap[o.Id]
    ? Object.assign({}, o, { Qty: o.Qty - oldMap[o.Id].Qty })
    : o;
});

const droppedOrders = oldOrder.filter(function (o) {
  return !newMap[o.Id];
});

console.log(result);
console.log(droppedOrders);
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }

Answer №2

Consider implementing Array.map and Array.filter

var initialOrders = [{ "Id": "10", "Qty": 1 }, { "Id": "3", "Qty": 2 }, { "Id": "9", "Qty": 2 }];
var updatedOrders = [{ "Id": "5", "Qty": 2 }, { "Id": "10", "Qty": 3 }, { "Id": "9", "Qty": 1 }];

const modifiedArray = updatedOrders.map((node) => {
  const nodeFromInitialOrders = initialOrders.find((item) => item.Id === node.Id);
  if (nodeFromInitialOrders) {
    return {
      Id: node.Id,
      Qty: nodeFromInitialOrders.Qty - node.Qty
    }
  } else {
    return node;
  }
});

const removedOrders = initialOrders.filter((item) => !modifiedArray.find(node => node.Id === item.Id))

console.log(modifiedArray);
console.log(removedOrders);

Answer №3

To accomplish this task, one effective method is to organize the old and new order arrays by their Id values. Once these arrays are properly organized, you can easily utilize filtering and mapping techniques:

var oldOrder = [{"Id": "10","Qty": 1}, {"Id": "3","Qty": 2}, {"Id": "9","Qty": 2}]; 
var newOrder = [{"Id": "5","Qty": 2},{"Id": "10","Qty": 3}, {"Id": "9","Qty": 1}];
    
var keyedOldOrder = keyBy(oldOrder, 'Id');
var keyedNewOrder = keyBy(newOrder, 'Id');

var newArray = newOrder.map(function (entity) {
  var subtract = keyedOldOrder.hasOwnProperty(entity.Id)
    ? keyedOldOrder[entity.Id].Qty
    : 0;
  return Object.assign({}, entity, {
    Qty: entity.Qty - subtract
  });
});

var droppedOrders = oldOrder.filter(function (entity) {
  return !keyedNewOrder.hasOwnProperty(entity.Id);
});

console.log(newArray);
console.log(droppedOrders);

function keyBy(array, field)
{
  return array.reduce(function (carry, entity) {
    carry[entity[field]] = entity;
    return carry;
  }, {});
}

Answer №4

You have the option to utilize a Map and execute a single loop for each array, then render the outcome to the desired target arrays.

const
    addToMap = (map, target) => ({ Id, Qty }) => map.set(Id, { target, Qty: Qty - (map.get(Id)?.Qty || 0) }),
    oldOrder = [{ Id: "10", Qty: 1 }, { Id: "3", Qty: 2 }, { Id: "9", Qty: 2 }],
    newOrder = [{ Id: "5", Qty: 2 }, { Id: "10", Qty: 3 }, { Id: "9", Qty: 1 }],
    map = new Map,
    orders = [],
    dropped = [];

oldOrder.forEach(addToMap(map, dropped));
newOrder.forEach(addToMap(map, orders));

map.forEach(({ target, Qty }, Id) => target.push({ Id, Qty }));

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

Alternatively, you can implement an older Javascript approach by using an object instead of Map.

The logic behind the algorithm remains the same as described above.

const
    addToMap = function(map, target) {
        return function (o) {
            map[o.Id] = { target: target, Qty: o.Qty - (map[o.Id] && map[o.Id].Qty || 0) };
        };
    },
    oldOrder = [{ Id: "10", Qty: 1 }, { Id: "3", Qty: 2 }, { Id: "9", Qty: 2 }],
    newOrder = [{ Id: "5", Qty: 2 }, { Id: "10", Qty: 3 }, { Id: "9", Qty: 1 }],
    map = {},
    orders = [],
    dropped = [];

oldOrder.forEach(addToMap(map, dropped));
newOrder.forEach(addToMap(map, orders));

Object
    .keys(map)
    .forEach(function(Id) {
        map[Id].target.push({ Id: Id, Qty: map[Id].Qty });
    });

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

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

Utilizing window.location.pathname in Next.js for precise targeting

Are you familiar with targeting window.location.pathname in NEXT.JS? I encountered a red error while using this code in Next.js const path = window.location.pathname console.log(path) // I am able to retrieve the pathname here Then { ...

By-passing Mistakes in Iteration in JavaScript

I have been working on using Google's Feed API to fetch images from a feed within an AngularJS controller. It successfully retrieves three images, but encounters an issue when it reaches a Twitter URL, causing the script to break. I would like it to s ...

Is my data secure in Node.js RAM?

I have developed a web application that enables users to create personal pages using Express and Node.JS. Each page is represented as an object, allowing for the creation of new ones with the syntax: new privatePage(name, pswd). As a result, all passwords ...

The configuration error occurred for the `get` action due to an unexpected response. Instead of an object, an array was received

Despite numerous attempts, I am struggling to find a solution that works for me. In my Courses controller, I am using the Students service and Staff service to access my staff and student objects. My goal is to retrieve the staffs and students objects in o ...

Is there a way to assign a role to a user without requiring them to send a message beforehand?

I've been searching for a solution to this issue, but all I could find were instructions on how to assign a server role to someone who has interacted in some way. Is there a way to locate a specific user on a server and assign a role to them without ...

How to refresh a page in React when the browser's back button is pressed

In my React project using Material-UI, I have created a simple search form. On page A, users can input values in text boxes and select options from drop-down lists and checkboxes. The results are then displayed on page B. My issue arises when returning to ...

How can the data controller of a model be accessed within a directive that has been defined with "this"?

I'm struggling with accessing data using a directive, especially when I have defined my models like this: vm = this; vm.myModel = "hello"; Here is an example of my directive: function mySelectedAccount(){ return { restrict: 'A&ap ...

Can Angular retrieve the inner HTML content of an element?

Check out this demo . In this demonstration, I have created a list of "names" and I'm trying to retrieve the text of the selected element. However, whenever I click on an item from the list, I consistently get the same "innerHTML" for all users. Is ...

Utilizing Vue.js to initiate a server request with vue-resource

Seeking guidance on performing a server call using vue-resource. I'm unsure about how to set the header and send data via Vue.$http.post Vue.$http.post('http://url/', { email: 'foo', password: 'bar' }, { headers: { ...

In Node.js, use the `[]` operator to select elements from an array of strings without including

In my situation, I am working with an array of strings which can sometimes be an array containing only one string. The issue is that when this happens, using array[0] to retrieve the value does not return the entire string but rather just the first charact ...

The PHP server is having trouble accepting a JavaScript object sent via AJAX

Hey there, I'm currently facing an issue with sending fields from a form saved in a JavaScript object to a PHP server. I have set up the AJAX communication, but when I try to access the object in PHP, I notice that the length is showing as 0 during de ...

What are some strategies for enhancing the efficiency of asynchronous data retrieval and caching?

I'm using this code to retrieve data asynchronously and store it in a cache for performance optimization: let cache = {} const optimizedFetch = async (url) => { if (url in cache) { // return cached result if available console.lo ...

The Ionic AngularJS http service is failing to update the controller

I'm struggling to understand why my controller is receiving an empty array after calling the service, which triggers an http call. Here's how I have set up my app: Here is my app.js file: //App.js .state('myApp.sermonlists', { u ...

Enhance your Django webpage with real-time updates using AJAX technology

[Revised for Clarity and Detail] The challenge I'm facing is related to the architecture of my project. I have multiple ideas on how to achieve my goal, but I'm stuck on identifying the correct or most efficient approach. To provide more context ...

Interactive JS chart for visually representing values within a preset range in Vue.js

I was in need of a custom JavaScript chart specifically designed to display a value within a specified upper and lower limit. The main application for this would be illustrating the current stock price between its 52-week high and low ranges. It was essent ...

Storing data in the browser's LocalStorage after a Vue3 component has

Whenever a user successfully logs into the application, a nav bar is supposed to load user data. However, there seems to be a timing issue with localStorage being set slightly after the nav bar is loaded. Using a setTimeout() function resolves the issue, b ...

What are the drawbacks of setting data from computed properties?

When working with vuex, I often come across a scenario where I receive an object like the following: user: {name: 'test'} In my app.vue file, I access this object using this.$store.getters.user computed: { user: function() { let user ...

Using ObjectIDs in MongoDB may be successful, however, it may not function properly in Mongoose

The desired effect is successfully achieved by the first code snippet shown below: //in mongodb console: db.collection.update({"username":"name"}, {$pull : { "task" : { "_id" : ObjectId("55280205702c316b6d79c89c")}}}) However, the second code snippet wri ...

Achieving the retrieval of all data can be done simply by utilizing the `echo json_encode($data);

I am trying to automatically update the user wall with new data from the database using a script that checks for updates every 15 seconds. Everything works fine when I only use one piece of data like $data = $row['description']; in the server.ph ...

Having trouble creating a polygon from JSON in ESRI ArcGIS Javascript framework?

Can anyone assist with understanding the issue of trying to draw a polygon using the ESRI ArcGIS Javascript API? The image, JSON string, and code snippets provided below outline the code, console output, and expected behavior. Any help would be greatly app ...