Refine collection of objects based on a separate set of objects

I need to filter an array of objects based on another array of objects.

I currently have two arrays of objects structured like this:

const array = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } },
    { id: 4, name: 'a4', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];
const anotherArray = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];

My goal is to filter the array using anotherArray, and only return items that do not exist in anotherArray and have a sub-object.

Therefore, the desired output would be:

[ { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } ] 

Note: I have achieved this using a for loop, but it runs too slow. I want to accomplish this using the Array's filter method

This is the code I currently have with a for loop:

for (let i = 0; i < array.length; i += 1) {
    let exist = false;
    const item = array[i];
    for (let j = 0; j < anotherArray.length; j += 1) {
      const anotherItem = anotherArray[j];
      if (item.id === anotherItem.id) {
        exist = true;
      }
    }
    if (item.sub && !exist) {
      this.newArray.push({
        text: `${item.sub.name} / ${item.name}`,
        value: item.id,
      });
    }
  }

Answer №1

As Felix pointed out, when it comes to performance, Array#filter may not be faster than a native for loop. However, if you prefer a more functional approach, here is one potential solution:

const array = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } },
    { id: 4, name: 'a4', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];

const anotherArray = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];

const result = array.filter((elem) => !anotherArray.find(({ id }) => elem.id === id) && elem.sub);

console.log(result);

Answer №2

If you're looking to filter an array and then check if any elements meet a certain condition without returning the element itself, you can utilize Array.filter along with Array.some. This approach is useful when you don't need the specific element returned like you would get with Array.find:

const a1 = [ { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } }, { id: 2, name: 'a2', sub: null }, { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } }, { id: 4, name: 'a4', sub: null }, { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } }, ]; 
const a2 = [ { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } }, { id: 2, name: 'a2', sub: null }, { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } }, ];

const result = a1.filter(({id, sub}) => !a2.some(x => x.id == id) && sub)

console.log(result)

Answer №3

If you want to compare two objects, consider using JSON.stringify for a basic comparison. For more thorough comparisons, create a function that recursively checks all properties of the objects.

const array = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 3, name: 'a3', sub: { id: 8, name: 'a3 sub' } },
    { id: 4, name: 'a4', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];
const anotherArray = [
    { id: 1, name: 'a1', sub: { id: 6, name: 'a1 sub' } },
    { id: 2, name: 'a2', sub: null },
    { id: 5, name: 'a5', sub: { id: 10, name: 'a5 sub' } },
];

const notIn = (array1, array2) => array1.filter(item1 => {
    const item1Str = JSON.stringify(item1);
    return !array2.find(item2 => item1Str === JSON.stringify(item2))
  }
);

console.log(notIn(array, anotherArray));

Answer №4

Alright, let's break it down step by step.

To streamline the process, let's assume that two elements are considered equal if they share the same id.

One way to approach this is by iterating through the first array and, for each element, checking against the conditions specified earlier in the second array.

const A = [ /* ... */]
const B = [ /* ... */]

A.filter(el => {
  let existsInB = !!B.find(e => {
    return e.id === el.id
  }

  return existsInB && !!B.sub
})

If we're confident that elements with the same ID in both arrays are truly identical, we can optimize further by skipping A elements without the sub property:

A.filter(el => {
  if (!el.sub) return false

  let existsInB = !!B.find(e => {
    return e.id === el.id
  }

  return existsInB
})

In cases where our arrays are larger, continuously searching for elements in B becomes inefficient. To address this, I usually convert the array into a map like so:

var BMap = {}
B.forEach(el => {
  BMap[el.id] = el
})

A.filter(el => {
  if (!el.sub) return false

  return !!BMap[el.id]
})

This method requires a bit of time upfront to create the map, but it significantly speeds up the subsequent element retrieval process.

There are more optimization strategies to consider beyond this point, but for now, these steps should suffice for your current query.

Answer №5

OPTIMIZED VERSION

const data = [{
    id: 1,
    name: "apple",
    type: {
      id: 6,
      category: "fruit"
    }
  },
  {
    id: 2,
    name: "banana",
    type: null
  },
  {
    id: 3,
    name: "orange",
    type: {
      id: 8,
      category: "citrus"
    }
  },
  {
    id: 4,
    name: "grapes",
    type: null
  },
  {
    id: 5,
    name: "kiwi",
    type: {
      id: 10,
      category: "exotic"
    }
  },
];
const filterData = [{
    id: 1,
    name: "apple",
    type: {
      id: 6,
      category: "fruit"
    }
  },
  {
    id: 2,
    name: "banana",
    type: null
  },
  {
    id: 5,
    name: "kiwi",
    type: {
      id: 10,
      category: "exotic"
    }
  },
];

const dictionary = filterData.reduce((acc, curr) => {
  const { id } = curr;
  acc[id] = curr;
  return acc;
}, {});

const finalResult = data.filter((obj) => {
  const searchValue = dictionary[obj.id];
  if (!searchValue && obj.type) return true;
  return false;
});

console.log(finalResult);

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

What is preventing me from being able to effectively transmit the array using the POST method in Express?

As a newcomer trying to learn Express, I believe I am on the right path, but I am currently facing some challenges with the POST method. The issue I'm encountering is as follows: Whenever I send a POST request to an HTTP file, I receive an empty ob ...

Guidance sought on utilizing a callback to retrieve data from mysql using node.js and ejs

I am trying to retrieve the value of foo from the query provided below: exports.get = function(id, cb) { sql = 'SELECT `sidebar`, `test` FROM users WHERE `id` = "' + id + '"'; con.query(sql, function(err, foo) { if (err) ...

Invoke an anchor element using JavaScript

I have successfully implemented Thickbox 3.1 to display a popup by using the following code: <a href="filename.php" class="thickbox"> TEST </a> When clicking on the "TEST" link, the popup works perfectly. However, my current issue is that I ...

Utilize jQuery to extract various input/select box values and compile them into an array for submission using .ajax()

I am currently facing an issue with dynamically generated forms using PHP and updated with jQuery's .appendTo() function as visitors interact with it. My main goal is to collect all input text and select box values from the current form and submit the ...

Putting off the execution of a setTimeout()

I'm encountering difficulties with a piece of asynchronous JavaScript code designed to fetch values from a database using ajax. The objective is to reload a page once a list has been populated. To achieve this, I attempted to embed the following code ...

MQTT Broker specialized in Typescript

I'm looking to create a MQTT Broker using TypeScript and Angular. I've attempted a few examples, but I keep encountering the following error: Uncaught TypeError: http.createServer is not a function Here's a simple example of what I'm c ...

Developing a collection of generic objects: D

Having trouble creating an array of Regex objects, specifically trying to do so with Regex[] regexes;. Unfortunately, the compilation is throwing an error: main.d(46): Error: template std.regex.Regex(Char) is used as a type. The documentation on this topi ...

AngularJS encounters failure during shared data service initialization

As a newcomer to AngularJS, I aim to develop an application in adherence to John Papa's AngularJS style guide. To familiarize myself with these best practices, I have opted for the HotTowel skeleton. My application requires consuming an HTTP API endp ...

Erase a chat for only one user within a messaging application

Currently, I am in the process of building a chat application using nodejs and mongodb. In order to structure my database properly, I have created two models: conversation and messages. Message.js conversationId: { //conversationID }, body: ...

How can I center align my loader inside app-root in Angular2+?

I've successfully added a basic spinner to my <app-root> in the index.html file. This gives the appearance that something is happening behind the scenes while waiting for my app to fully load, rather than showing a blank white page. However, I& ...

A step-by-step guide on generating orders and order line items in Odoo with the help of Node.js

Struggling to create orders and add order-lines to the odoo database? Getting stuck with an error message faultString: ('The requested operation ("create" on "Sales Order" (sale.order)) was rejected because of the following rules:\\n\&b ...

Implementing a Jquery check based on a checkbox

Hey, I'm having an issue with a condition. When I uncheck the checkbox, it doesn't uncheck. I've tried to make a block display, but the JavaScript isn't working. I attempted to add: document.getElementById("Reload").style.display = "b ...

Enhancing Promises.all with extra parameters

Looking to dive into promises, eager to learn. Here is an array of shopIds I'm working with: let shopIdsArray = ['shop1','shop2','shop3']; Additionally, there's an external promise call: getProducts(shopId, ' ...

Preventing a draggable item from being dropped into a sortable container when the maximum count has been reached

Check out the following code snippet: <link rel="stylesheet" href="//code.jquery.com/ui/1.11.0/themes/smoothness/jquery-ui.css"> <script src="//code.jquery.com/jquery-1.10.2.js"></script> <script src="//code.jquery.com/ui/1.11.0/jquer ...

How does the max() function in JavaScript handle arrays when there are multiple numbers of the same maximum value?

Assuming we have the following scenario: array=[5,5,5,5,3,2]; return Math.max.Apply(Math,array); How can I modify the code to output the numbers in sequential order from first to last? ...

Encountering the "Invalid Element Type" error in a Vue Native project right after setting it up

After creating a vue-native project with the command vue-native init henry-pager, I navigated to the directory and initiated the online builder by running expo start. However, when attempting to run it on the web platform, an error message appeared: Error: ...

Tips for creating and showcasing links from a PHP array using the "WHERE" clause

Here is a PHP array containing categories: $category = array( 1 => array( 'id' => 1, 'parentID' => 0, 'name' => 'SUV auto parts' ), 2 => array( &apo ...

Why does React-Perfect-Scrollbar not work properly when the height of an element is not specified in pixels?

Currently, I am developing a chat application with React 18 for its user interface. The app includes a sidebar that displays user profiles. To ensure the app fits within the browser window height, I've made the list of user profiles scrollable when n ...

Incorporating Dynamic Javascript: A Step-by-Step Guide

I came across a select object that looks like this: <select id="mySelect" onchange = "start()" > <option>Apple</option> <option>Pear</option> <option>Banana</option> <option>Orange</option> < ...

The babel-preset-es2016 plugin is in need of the babel-runtime peer dependency, however it seems that it

While I am aware that npm no longer automatically installs peer dependencies, why do I still receive a warning after manually installing them? ➜ npm install babel-runtime -g /usr/local/lib └─┬ <a href="/cdn-cgi/l/email-protect ...