What is the best way to sort an array of objects based on their properties?

I am working with an array of objects:

let response = [{"id": 1, "name": "Alise", "price": 400, "category": 4}];

In addition to the array of objects, I have some arrays that will be used for filtering:

let names = ["Jessy", "Megan"];
let prices = [300, 500];
let category = [1,2,4];

My goal is to filter the array using these filtering arrays with a condition of AND between names, prices, category, and an OR condition between elements in each array: JessyOR Megan .etc

To tackle this issue, I came up with the following solution:

const filterByCategory = (response: IResponse[], filterBy: any[]) => response.filter((e: IResponse) => filterBy.indexOf(e.category) > -1);
const filterByPrice =  (response: IResponse[], filterBy: any[]) => response.filter((e: IResponse) => e.price in filterBy);

Now, I'm unsure about how to make the call more efficient:

First approach:

filter() {
  let filtered = filterByCategory(response, category);
  filtered = filterByPrice(filtered, prices);
}

Second approach:

filter() {
   let filtered = [];
   if (category && category.length) {
      filtered = filterByCategory(response, category);
   }

   if (prices && prices.length) {
       filtered = filterByCategory(filtered, category);
   }
}

Third approach:

let filtered = response.filter((element) => {
    return category && category.indexOf(e.category) > -1 && 
    prices && prices.indexOf(e.price) > -1 && etc.
});
  • The first approach allows for easy modification of the filtering logic without changing the main filter.
  • The second approach is similar to the first but includes additional checks.
  • The third approach is the shortest, but may be difficult to modify in the future.

Answer №1

This example demonstrates the importance of clarity, conciseness, and maintainability in coding.

const filteredItems = response.filter(e => {
    const validations = {
       containsCategory: category && category.includes(e.category),
       containsPrice: prices && prices.includes(e.price),
       containsName: names && names.includes(e.name),
    };

    return Object.values(validations).every(v => v);
});

The use of an object in this scenario allows for better organization and ease of iteration to check each validation's truth value. By avoiding duplicate code through individual variable definitions for each validation, the process is streamlined.

const filteredItems = response.filter(e => {
   const containsCategory = category && category.includes(e.category);
   const containsPrice = prices && prices.includes(e.price);
   const containsName = names && names.includes(e.name);

   return containsName && containsPrice && containsName;
});

This approach eliminates the need to update validation names in multiple places when adding new ones. Additionally, it provides flexibility for expanding validation categories in the future, unlike more concise solutions that may have limitations.

Furthermore, enhancements such as string filters or advanced filter functions can easily be integrated into the validations structure:

const validations = {
   matchesSearchString: !searchString || e.name.toLowerCase().startsWith(searchSting.toLowerCase()),
   isAnAncientQueen: isAnAncientQueen(e.name),
   /* -- snip -- */
};

Answer №2

While other answers may be more concise, leveraging TypeScript's type system can provide a safe and versatile solution. The preference for such an approach depends on the specific requirements relating to type safety and maintainability.

A generic method would involve defining a filter type that is applicable to any object, followed by implementing a function capable of applying this filter to an array of diverse types.

An example of the "filter" implementation is:

type Filter<T> = {
    [P in keyof T]?: (T[P])[]
}

This can be interpreted as "for every member of type X in T, Filter<T> will have an optional array of type X[] with the same name."

The filter function would be as follows:

function filter<T>(items: T[], filter: Filter<T>): T[]{
    // interim result for easier debugging
    let result =
        items.filter(
            item => {
                // check each member in the filter
                for (let key in filter) {
                    let valueInFilter = filter[key];
                    // if it's empty, then it's OK
                    if (valueInFilter) {
                        // otherwise the value on item MUST be found in the array on filter
                        let valueInItem = item[key];
                        if (valueInFilter.indexOf(valueInItem) == -1) {
                            return false;
                        }
                    }
                }

                // if every check passes, keep the item
                return true;
            }
        );

    return result;
}

Combining all elements, an example usage could resemble the following:

let responses: IResponse[] = [
    { "id": 1, "name": "Alise", "price": 400, "category": 4 },
    { "id": 2, "name": "Bob", "price": 300, "category": 2 }
];

let someFilter: Filter<IResponse> = {
    id: [1, 2, 4],

    price: [300]
};

console.log(filter(responses, someFilter))

This was tested on the TypeScript Playground to ensure all type checking functions correctly.

Answer №3

If you want to implement the `Array.prototype.filter()` function for fulfilling both `AND` and `OR` conditions, you can utilize `Array.prototype.every()` for `AND` condition and `Array.prototype.some()` for `OR` condition:

const response = [{"id": 1, "name": "Alise", "price": 400, "category": 4},{id:2, name:'Megan', price:300, category:2}],
      name = ["Jessy", "Megan"],
      price = [300, 500],
      category = [1,2,4],
      filters = {name,price,category},
      
      
      result = response.filter(o => Object
        .entries(filters)
        .every(([key,values]) => 
          !values.length || values.some(value => o[key] == value)
        )
      )
          
console.log(result)

In comparison to using `Array.prototype.includes()`-based methods, this approach may be more scalable if you require a non-strict match in the future (like case-insensitive partial matching to specific keywords).

Answer №4

Array.prototype.includes acts as the filter for either/or conditions among collection values, while && serves as the filter for and conditions:

let response = [{"id": 1, "name": "Megan", "price": 500, "category": 4}];

let names = ["Jessy", "Megan"];
let prices = [300, 500];
let category = [1,2,4];

const filteredItems = response.filter(item => {
  return names.includes(item.name) && 
      prices.includes(item.price) &&
      category.includes(item.category);
});

console.log(filteredItems)

Answer №5

To determine compatibility between the key and values, you can utilize the `includes` method along with a filter function applied to the object.

let
    filter = ([key, values]) => o => !values.length || values.includes(o[key]),
    constraints = {
        id: [], // empty - take all values
        name: ["Jessy", "Megan"],
        price: [300, 500],
        category: [1, 2, 4]
    }
    filters = Object.entries(constraints).map(filter),
    response = [{ id: 1, name: "Alise", price: 400, category: 4 }, { id: 2, name: "Megan", price: 300, category: 4 }],
    result = response.filter(o => filters.every(fn => fn(o)));

console.log(result);
.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

If the value of the input matches, set the checkbox to be

I have successfully implemented functionality that allows the value of an input to be changed by clicking a checkbox. This works without any issues. Now, I am facing the challenge of automatically checking the checkbox when the page loads, but only if the ...

Tips for creating a versatile generic function in javascript that covers all arguments sizes

When working with node.js, a tcp server typically has several methods for listening: server.listen(port, [host], [backlog], [listeningListener]) server.listen(path, [listeningListener]) server.listen(handle, [listeningListener]) In the context of creatin ...

Efficiency of Promise-based parallel insert queries in MySQL falls short

I have developed a code in Node.js to execute insert queries using Promise.js but unfortunately, I am encountering an exception stating "Duplicate Primary Key" entry. Here is the snippet of the code: var Promise = require("promise"); var mySql = requir ...

CSS Switchable Style Feature

I am in need of some assistance with the navigation on my website. You can find the current code at this link: http://jsfiddle.net/Sharon_J/cf2bm0vs/ Currently, when you click on the 'Plus' sign, the submenus under that category are displayed bu ...

Tips for incorporating a JavaScript file directly into your HTML code

I'm working with a compact javascript file named alg-wSelect.js, containing just one line of code: jQuery('select.alg-wselect').wSelect(); This script is used by a wordpress plugin. My question is whether it's feasible to incorporate th ...

Focus is lost on React input after typing the initial character

Whenever I input text, the focus is lost. All my other components are working fine except this one. Any ideas why this might be happening? I attempted to create separate components and render them in my switch statement, but it still doesn't work. O ...

What is causing the issue of the div not being removed from the label renderer in three.js

Hello, I've been trying to solve this issue for the third time now without much success. The problem I'm facing is related to creating a div at runtime and then attempting to remove it after clicking on it. Although I've tried removing the d ...

Tips for making Google search results include query strings in the returned links

I need help figuring out how to make Google search results show a URL containing a query string. Here's an example from the project I am currently working on: Instead of this link, Google search returns: If anyone has any suggestions for fixing this ...

The event failed to initiate

I have an event that is fired when the number value changes in the <input type="number"> below: <input type="number" inputmode="numeric" pattern="[0-9]*" size="4" class="lorem" value="0" step="1"> <input type="button" class="minus" value=" ...

Introducing the concept of type-specific name inclusion

I am currently developing my Angular app using TypeScript with the goal of preventing redundancy through some form of generic handling. Here is where I am starting: class BaseProvider { api_url = 'http://localhost:80/api/FILL_OUT_PATH/:id&apo ...

What could be causing my object to not be added properly to a select element using JavaScript programmatically?

When it comes to customizing your pizza, the options are endless. From selecting the type of crust to choosing your favorite toppings, every detail matters. One common issue that arises is when changing the crust type affects the available sizes ...

Trouble displaying loaded JSON data with $http GET in ng-table

I have recently delved into learning angularjs and am currently experimenting with using ng-table to display the results of blast searches. Everything runs smoothly when I directly add the JSON data in the JavaScript script. However, I have been unsuccess ...

What is the best way to develop a unique animation for every v-card?

Is there a way to customize each animation so that it is specific to the selected v-card? Right now, when one card is clicked, all of them play the same animation. data: () => ({ show: true, images: [ {url:require('@/assets/london. ...

Tips for modifying an HTML element's attribute when a button is clicked, both in the client and server side

Context: This question delves into the fundamental concepts of AJAX. I have been studying this tutorial along with this example for the JavaScript part, and this resource (the last one on the page) for the PHP segment. Imagine a scenario where a JavaScri ...

Tips on incorporating Angular ng-include

As a newcomer to AngularJS on an Express Framework, I am facing an issue with loading HTML pages as includes. Although my routing in Angular is set up correctly and functioning well, when I try to use ng-include in my HTML pages, it results in a loop and t ...

Tips on passing an object as data through Angular router navigation:

I currently have a similar route set up: this.router.navigate(["/menu/extra-hour/extra-hours/observations/", id]) The navigation is working fine, but I would like to pass the entire data object to the screen in order to render it using the route. How can ...

Ways to properly close open HTML tags using node.js?

Have you ever encountered a situation where user-entered content from a database or similar source only contains the opening tag without the closing tag? This can disrupt the layout of your website. Is there a way to fix this issue using Node.js on the s ...

Load Angular modules dynamically

Is there a way to dynamically load a module (js, css and html) using a single directive at any point during the app's lifecycle? <my-module id="contacts"></my-module> The template for this directive looks like this <my-module id="con ...

Guide on how to modify the color of a single row within a table with just a click

My table structure is as follows: <table> <tr> <td>A1</td> <td>A2</td> <td>A3</td> <td>A4</td> </tr> <tr> ...

Customize the CSS for material-ui buttons or create a new style altogether

Looking to customize the background color of a material UI RaisedButton, I have encountered a challenge. This is what I currently have: const style = { backgroundColor: 'green' }; export default class CreateLinksave extends React.Component { ...