Is there a way for me to determine if there are elements in one object array that exist in another object

Is there a method to check if two object arrays have any common elements, and if so, find the intersecting object? Similar to a Contains function. For instance, in the provided example, ProductId3 in Object Array 1 is also present in Object Array 2.

I'm considering using a nested loop, but I'm wondering if there is a more efficient or concise way to achieve this, perhaps using an ECMA or lodash function.

Note: We are comparing all object attributes, not just ProductId.

array1.forEach(arr1 => {
  array2.forEach(arr2 => { 
       if (arr1.productId === arr2.productId && 
           arr1.productName === arr2.productName ...)

Object Array 1:

[
{
    ProductId: 50,
    ProductName: 'Test1',
    Location: 77,
    Supplier: 11,
    Quantity: 33
},
{
    ProductId: 3,
    ProductName: 'GHI',
    Location: 1,
    Supplier: 4,
    Quantity: 25
}
]

Object Array 2:

[
{
    ProductId: 1,
    ProductName: 'ABC',
    Location: 3,
    Supplier: 4,
    Quantity: 52
},
{
    ProductId: 2,
    ProductName: 'DEF',
    Location: 1,
    Supplier: 2,
    Quantity: 87
},
{
    ProductId: 3,
    ProductName: 'GHI',
    Location: 1,
    Supplier: 4,
    Quantity: 25
},
{
    ProductId: 4,
    ProductName: 'XYZ',
    Location:  5,
    Supplier: 6,
    Quantity: 17
}
]

Resources:

How to determine if Javascript array contains an object with an attribute that equals a given value?

Javascript: Using `.includes` to find if an array of objects contains a specific object

Answer №1

Is there a method to determine if two arrays of objects have any common elements? - Yes, you can accomplish this using the Array.some() method. This method returns true if it finds an element in the array for which the provided function returns true, otherwise it returns false.

const array1 = [{
  ProductId: 50,
  ProductName: 'Test1',
  Location: 77,
  Supplier: 11,
  Quantity: 33
}, {
  ProductId: 3,
  ProductName: 'GHI',
  Location: 1,
  Supplier: 4,
  Quantity: 25
}];

const array2 = [{
  ProductId: 1,
  ProductName: 'ABC',
  Location: 3,
  Supplier: 4,
  Quantity: 52
}, {
  ProductId: 2,
  ProductName: 'DEF',
  Location: 1,
  Supplier: 2,
  Quantity: 87
}, {
  ProductId: 3,
  ProductName: 'GHI',
  Location: 1,
  Supplier: 4,
  Quantity: 25
}, {
  ProductId: 4,
  ProductName: 'XYZ',
  Location:  5,
  Supplier: 6,
  Quantity: 17
}];

const hasCommonProducts = array2.some(({ ProductId }) => array1.map(obj => obj.ProductId).includes(ProductId));

console.log(hasCommonProducts);

Update: According to the author's comment, we need to compare all the properties of an object. Therefore, we can achieve this by comparing the JSON strings after converting the objects into strings.

Live Demo:

const array1 = [{
  ProductId: 50,
  ProductName: 'Test1',
  Location: 77,
  Supplier: 11,
  Quantity: 33
}, {
  ProductId: 3,
  ProductName: 'GHI',
  Location: 1,
  Supplier: 4,
  Quantity: 25
}];

const array2 = [{
  ProductId: 1,
  ProductName: 'ABC',
  Location: 3,
  Supplier: 4,
  Quantity: 52
}, {
  ProductId: 2,
  ProductName: 'DEF',
  Location: 1,
  Supplier: 2,
  Quantity: 87
}, {
  ProductId: 3,
  ProductName: 'GHI',
  Location: 1,
  Supplier: 4,
  Quantity: 25
}, {
  ProductId: 4,
  ProductName: 'XYZ',
  Location:  5,
  Supplier: 6,
  Quantity: 17
}];

const filteredProducts = array2.filter(productObj => JSON.stringify(array1).indexOf(JSON.stringify(productObj)) !== -1);

console.log(filteredProducts);

Answer №2

If we assume that all sub-dictionaries within each array contain the same keys in the same order, here is my approach:

  1. Convert each array into a new array where the elements are the JSON representations of the original sub-dictionaries' values. This operation has a time complexity of O(N) and is done twice.
  2. Identify the shortest array among the newly converted arrays. Convert the other array into a set. This operation also has a time complexity of O(N).
  3. For each element in the shorter converted array, check if the set contains that value. This operation also has a time complexity of O(N).

let arr1 = [
{
    ProductId: 50,
    ProductName: 'Test1',
    Location: 77,
    Supplier: 11,
    Quantity: 33
},
{
    ProductId: 3,
    ProductName: 'GHI',
    Location: 1,
    Supplier: 4,
    Quantity: 25
}
];

let arr2 = [
{
    ProductId: 1,
    ProductName: 'ABC',
    Location: 3,
    Supplier: 4,
    Quantity: 52
},
{
    ProductId: 2,
    ProductName: 'DEF',
    Location: 1,
    Supplier: 2,
    Quantity: 87
},
{
    ProductId: 3,
    ProductName: 'GHI',
    Location: 1,
    Supplier: 4,
    Quantity: 25
},
{
    ProductId: 4,
    ProductName: 'XYZ',
    Location:  5,
    Supplier: 6,
    Quantity: 17
}
];

// Convert each sub-array's values to JSON string:
let arr1New = arr1.map(function(arr) {return JSON.stringify(Object.values(arr));});
let arr2New = arr2.map(function(arr) {return JSON.stringify(Object.values(arr));});

// Find shortest array of JSON strings:
const l1 = arr1New.length;
const l2 = arr2New.length;
// enumerate shortest list
let list, set, l, arr;
if (l1 <= l2) {
    list = arr1New;
    set = new Set(arr2New);
    l = l1;
    arr = arr1;
}
else {
    list = arr2New;
    set = new Set(arr1New);
    l = l2;
    arr = arr2;
}

for(let i = 0; i < l; i++) {
    if (set.has(list[i])) {
        console.log(arr[i]);
    }
}

Update

If the sub-dictionary keys are not in the same order, we need to create new sub-dictionaries where the keys are sorted:

// Create function to create new dictionaries sorted by keys

function sort_dict(d) {
    items = Object.keys(d).map(function(key) {
        return [key, d[key]];
    });
    items.sort(function(first, second) {
        return first[0] < second[0] ? -1 : (first[0] > second[0] ? 1 : 0);
    });
    sorted_dict = {};
    items.forEach(function(x) {
        sorted_dict[x[0]] = x[1];
    });
    return(sorted_dict);
}

// Modified lines:
// Convert each sub-array's values to JSON string:
let arr1New = arr1.map(function(arr) {return JSON.stringify(Object.values(sort_dict(arr)));});
let arr2New = arr2.map(function(arr) {return JSON.stringify(Object.values(sort_dict(arr)));});

Modified Code

let arr1 = [
{
    ProductId: 50,
    ProductName: 'Test1',
    Location: 77,
    Supplier: 11,
    Quantity: 33
},
{
    ProductName: 'GHI',
    Location: 1,
    Supplier: 4,
    Quantity: 25,
    ProductId: 3 // Key not in the same order
}
];

let arr2 = [
{
    ProductId: 1,
    ProductName: 'ABC',
    Location: 3,
    Supplier: 4,
    Quantity: 52
},
{
    ProductId: 2,
    ProductName: 'DEF',
    Location: 1,
    Supplier: 2,
    Quantity: 87
},
{
    ProductId: 3,
    ProductName: 'GHI',
    Location: 1,
    Supplier: 4,
    Quantity: 25
},
{
    ProductId: 4,
    ProductName: 'XYZ',
    Location:  5,
    Supplier: 6,
    Quantity: 17
}
];


function sort_dict(d) {
    items = Object.keys(d).map(function(key) {
        return [key, d[key]];
    });
    items.sort(function(first, second) {
        return first[0] < second[0] ? -1 : (first[0] > second[0] ? 1 : 0);
    });
    sorted_dict = {};
    items.forEach(function(x) {
        sorted_dict[x[0]] = x[1];
    });
    return(sorted_dict);
}

// Convert each sub-array's values to JSON string:
let arr1New = arr1.map(function(arr) {return JSON.stringify(Object.values(sort_dict(arr)));});
let arr2New = arr2.map(function(arr) {return JSON.stringify(Object.values(sort_dict(arr)));});

// Find shortest array of JSON strings:
const l1 = arr1New.length;
const l2 = arr2New.length;
// enumerate shortest list
let list, set, l, arr;
if (l1 <= l2) {
    list = arr1New;
    set = new Set(arr2New);
    l = l1;
    arr = arr1;
}
else {
    list = arr2New;
    set = new Set(arr1New);
    l = l2;
    arr = arr2;
}

for(let i = 0; i < l; i++) {
    if (set.has(list[i])) {
        console.log(arr[i]);
    }
}

Answer №3

One efficient approach is to create a Set containing the productIds from the first array. Next, filter the second array based on the ids from the first array, allowing you to iterate through each array only once with a time complexity of O(n).

let arr1 = [
  {
    ProductId: 50,
    ProductName: "Test1",
    Location: 77,
    Supplier: 11,
    Quantity: 33,
  },
  {
    ProductId: 3,
    ProductName: "GHI",
    Location: 1,
    Supplier: 4,
    Quantity: 25,
  },
];

let arr2 = [
  {
    ProductId: 1,
    ProductName: "ABC",
    Location: 3,
    Supplier: 4,
    Quantity: 52,
  },
  {
    ProductId: 2,
    ProductName: "DEF",
    Location: 1,
    Supplier: 2,
    Quantity: 87,
  },
  {
    ProductId: 3,
    ProductName: "GHI",
    Location: 1,
    Supplier: 4,
    Quantity: 25,
  },
  {
    ProductId: 4,
    ProductName: "XYZ",
    Location: 5,
    Supplier: 6,
    Quantity: 17,
  },
];

const getCommonItems = (arr1, arr2) => {
  let firstIdSet = new Set(arr1.map((product) => product.ProductId)); //1
  return arr2.filter((product) => firstIdSet.has(product.ProductId)); //2
};

console.log(getCommonItems(arr1, arr2));

Answer №4

If you're looking for a comprehensive equality comparison (for nested objects or all (key, value) pairs), I recommend a more efficient approach using base64 encoding/decoding to enhance performance in the comparison process. Here's how I tackle it:

  1. Merge the arrays and convert the object to base64 strings.
  2. Group similar objects together
  3. Identify and filter out duplicates
  4. Decode the base64 strings back to their original objects.

const convertObjToBase64 = o => btoa(JSON.stringify(o));
const convertBase64ToObj = str => JSON.parse(atob(str));
const arrayToObjCount = arr => arr.reduce((res, v) => {
  res[v] = (res[v] ?? 0) + 1;
  return res;
}, {});

const findDuplicateObjectsInMultipleArrays = (...arrays) => {
  const base64Array = Array.from(arrays.flat(), convertObjToBase64);
  const objCount = arrayToObjCount(base64Array);
  const duplicates = Object.entries(objCount).reduce((prev, [k, v]) => {
    if (v > 1) {
      prev.push(convertBase64ToObj(k));
    }
    return prev;
  }, []);
  return duplicates;
}

let arr1 = [{
    ProductId: 50,
    ProductName: 'Test1',
    Location: {
      LocationId: 77,
      LocationName: 'Location 77'
    },
    Supplier: 11,
    Quantity: 33
  },
  {
    ProductId: 3,
    ProductName: 'GHI',
    Location: {
      LocationId: 1,
      LocationName: 'Location 1'
    },
    Supplier: 4,
    Quantity: 25
  }
];

let arr2 = [{
    ProductId: 1,
    ProductName: 'ABC',
    Location: {
      LocationId: 3,
      LocationName: 'Location 3'
    },
    Supplier: 4,
    Quantity: 52
  },
  {
    ProductId: 2,
    ProductName: 'DEF',
    Location: {
      LocationId: 1,
      LocationName: 'Location 1'
    },
    Supplier: 2,
    Quantity: 87
  },
  {
    ProductId: 3,
    ProductName: 'GHI',
    Location: {
      LocationId: 1,
      LocationName: 'Location 1'
    },
    Supplier: 4,
    Quantity: 25
  },
  {
    ProductId: 4,
    ProductName: 'XYZ',
    Location: {
      LocationId: 5,
      LocationName: 'Location 5'
    },
    Supplier: 6,
    Quantity: 17
  }
];

let arr3 =[ 
  {
    ProductId: 2,
    ProductName: 'DEF',
    Location: {
      LocationId: 1,
      LocationName: 'Location 1'
    },
    Supplier: 2,
    Quantity: 87
  },
  {
    ProductId: 3,
    ProductName: 'GHI',
    Location: {
      LocationId: 2,
      LocationName: 'Location 2'
    },
    Supplier: 4,
    Quantity: 25
  },
   {
    ProductId: 4,
    ProductName: 'XYZ',
    Location: {
      LocationId: 6,
      LocationName: 'Location 5'
    },
    Supplier: 6,
    Quantity: 17
  }
];
console.log(findDuplicateObjectsInMultipleArrays(arr1, arr2, arr3));

Answer №5

Here are two solutions that can be implemented:

First Solution emphasizes readability: While the code may not be fully optimized for performance, it is written in a readable and elegant manner.

Link to Playground with working code

Firstly, a method is required to compare two objects of any type. This method compares only first-level properties, with nested object properties being compared by reference.

const areTheSame = (a: any, b: any) => {
  const objAProps = Object.keys(a).filter(key => typeof a[key] !== "function")
  const objBProps = Object.keys(b).filter(key => typeof b[key] !== "function")

  if (objAProps.length !== objBProps.length) {
    return false;
  }

  return objAProps.every((propName) => a[propName] === b[propName]);
}

Following this, a readable intersect method can be implemented to work with any array types:

const getIntersection = (array1: Array<any>, array2: Array<any>) => {
  return array1.filter(a1Item => array2.some(a2Item => areTheSame(a1Item, a2Item)));
}

The Second solution prioritizes performance, although it may sacrifice readability:

Initially, the hash for all objects is calculated, and then the intersection is identified based on that hash within a single forEach loop. While md5 is used in this example, any hash algorithm or library can be utilized.

Here is the Stack Blitz Playground link for this performance-oriented solution (ignore import errors).


const getArrayIntersection = (
  firstArray: Array<any>,
  secondArray: Array<any>
) => {
  const array1Hashed = firstArray.map((i) => md5(JSON.stringify(i)));
  const array2Set = new Set(secondArray.map((i) => md5(JSON.stringify(i)));

  const result: Array<any> = [];

  array1Hashed.forEach((itemHash, index) => {
    if (array2Set.has(itemHash)) {
      result.push(firstArray[index]);
    }
  });
  return result;
};

Answer №6

Building on @Rohìt Jíndal's point, you have the ability to verify if an array contains a particular object using the following method:

const targetObject = arr1.filter(obj => obj.id === "whatever" && obj.productname === "whatever") // ETC ETC

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

Is there a way I can utilize a for-loop and if statement in JavaScript to present the information accurately within the table?

My current task involves fetching data via AJAX and then using a for-loop and if-statement to determine which goods belong in each shopping cart. Once identified, I need to display these goods in separate tables corresponding to each customer. Although the ...

Removing an item from an array stored in jQuery using the .data() method

Utilizing the .data() method in jQuery, I have saved an array as shown below: var myArray = {}; myArray[0] = {}; myArray[0][0] = "test00"; myArray[0][1] = "test01"; myArray[1] = {}; myArray[1][0] = "test10"; myArray[1][1] = "test11"; $('#datastorage ...

Learn the technique in Vue to separate a string using commas and store the values in an array

As a Ruby enthusiast, I am delving into the world of Vue. In my project, users can input multiple styleCodes separated by commas. I aim to store these styleCodes in an array for flexible length calculations. See my code snippet below: <template> &l ...

Dismiss the necessity of imports in Angular

I am facing an issue with using a library in Angular, specifically the cubing npm package. This library is designed to run in both the browser and node environments, with specific code for each. I want it to run in the browser, but when compiling with Angu ...

Acquire data from an array of objects using JavaScript

I've written some code where I'm attempting to display certain values in HTML. Specifically, I am looking to extract the values from the "current" object: ("dt":1643884851, "temp":8.11, "description":"few clouds", and "icon":"02d") In addition, ...

What is the significance of $($(this)) in coding jargon

While browsing the internet, I came across a code snippet that includes the following line: if ($($(this)).hasClass("footer_default")) { $('#abc') .appendTo($(this)) .toolbar({position: "fixed"}); } I'm curious ab ...

Trigger a random tune when hovering the mouse

I need help figuring out how to make a fixed image on my page trigger a random sound track when hovered over. The sound could be one of five different tracks. Here is the HTML for my image: <img src="images/Airplane.png" class="Airplane-photo"> Bel ...

Ensuring proper input with JavaScript form validation

Currently, I am working on implementing a basic form validation feature, but it is not functioning as intended. The desired behavior is for the field border to change color to green or red based on its validity, while displaying text indicating whether t ...

Is it possible to modify the output type of a function depending on a parameter's characteristic?

In my code, I have a custom utility function that wraps document.querySelector function querySelector<T extends HTMLElement>(selector: string) { return document.querySelector<T>(selector); } I modified it to include an option to throw an e ...

There is no overload that matches this call while looping through Node.js process events

Incorporating a certain library automatically includes uncaughtException and unhandledRejection listeners, which I want to remove. Here's the code snippet: ["unhandledRejection", "uncaughtException"].forEach((eventName) => process .listener ...

Accessing Typescript module-level functions within a jQuery event handler while maintaining the original 'this' reference

Apologies for the awkward phrasing, I struggled to find the right words (which also made it tough to search for a solution). Consider the following TypeScript code: module Foo { function Bar(elem: JQuery) { // Do something here. } fu ...

Tips for generating a numeric whole number input field with Vuetify

After researching the topic on Vuetify's specific number input component, I am attempting to create a numeric input field. The value for both input and output is currently unknown, meaning it could be either undefined or null in order to allow cleari ...

What steps can be taken to initiate Nx Release on the apps/* when modifications are made to the connected libs/* modules?

Trying out the nx release command but struggling to get it to release an app when there are changes to a dependent module. Examining the graph below, you can see that I have 3 apps, with 2 depending on the shared-ui module. https://i.sstatic.net/QYDBlRnZ.p ...

What is the method to effectively conduct a testing procedure for JavaScript files that have been exported using

I have a JavaScript file called "sum.js" which contains a simple function: // sum.js function sum(a, b) { return a + b; } export default { sum }; Now I want to write a test for this file using Jest. Here is my "sum.test.js" file in the same folder: // ...

Is it possible to perform a PHP redirect after the headers have been

I am encountering an issue with a function that needs to redirect the page once a variable is set. The challenge arises from the fact that this function is located at the bottom of the PHP page. As a result, I have already displayed a significant amount ...

What is the best way to display the current scroll percentage value?

I'm trying to update this code snippet import React from 'react' const App = () => { function getScrollPercent() { var h = document.documentElement, b = document.body, st = 'scrollTop', sh = 'scrollHeight ...

Utilizing CakePHP 3.0 with jQuery UI for an autocomplete feature

Seeking assistance on why the current code isn't functioning. The objective is to retrieve data from the index controller to search and obtain JSON data. No requests are being made, and there are no visible results. New to CakePHP 3.0, I am attemptin ...

X-Ray Rendering in Three.js and Webgl

Looking to create an x-ray effect in three.js / webgl. Something like this: UPDATE I am seeking help on how to achieve a real-time render with the x-ray effect, instead of just a static image. This can be accomplished using shaders that modify density i ...

The creation of the ESLint CLIEngine encountered some issues

Encountered an issue while setting up the ESLint CLIEngine - 'basePath' must be an absolute path Attempting to utilize eslint $ npx prettier-eslint **/*.js However, receiving the following error message: prettier-eslint [ERROR]: Encountered a ...

Is there a way to ensure that a statement will not execute until the completion of a preceding function?

I am encountering an issue where the window.open function is being called too quickly, causing my other function not to finish and post in time within my onclick event. I attempted to address this by setting a timeout on the trackData() function, but it o ...