Sorting through an array using several filter arrays

Is there a way to efficiently filter an array of items based on multiple filter arrays? Each item has various filters, and I want to display only the ones that match all selected filters.

const selectedFilters = {
    color: ["Red", "Blue"],
    type: ["Shirt"],
    size: ["M"]
};

const items = [
    {
        name: "Item 1",
        filters: {
            color: ["Red", "Blue", "Black"],
            type: ["Shirt"],
            size: ["M"]
        }
    },
    {
        name: "Item 2",
        filters: {
            color: ["Red"],
            type: ["Pants"],
            size: ["M"]
        }
    }
];

I'm attempting to address this issue by iterating through all items and checking if each one satisfies all selected filters.

const filterItems = (items, selectedFilters) => {
    const filterKeys = Object.keys(selectedFilters);

    return items.filter(item => {
        return filterKeys.every(key => {

            // Skip empty filters
            if (!selectedFilters[key].length) {
                return true;
            }

            return selectedFilters[key].every(filterWord => {
                item.filters[key].includes(filterWord);
            });
        });
    });
};

filterItems(items, selectedFilters);

Although the current implementation results in an empty array, the expected output should include the "Item 1" object.

Answer №1

To begin, generate an array containing the values of the selectedFilters as well as an array of values from the filters property. Next, utilize the every method on the selectedFilters array to verify if all values within it are included in the filters array.

const selectedFilters = {
    color: ["Red", "Blue"],
    type: ["Shirt"],
    size: ["M"]
};

const items = [
    {
        name: "Item 1",
        filters: {
            color: ["Red", "Blue", "Black"],
            type: ["Shirt"],
            size: ["M"]
        }
    },
    {
        name: "Item 2",
        filters: {
            color: ["Red"],
            type: ["Pants"],
            size: ["M"]
        }
    }
];

const filterArr = Object.values(selectedFilters).flat();

const output = items.filter(({filters}) => {
    const objFilters = Object.values(filters).flat();
    return filterArr.every(val => objFilters.includes(val));
})
console.log(output);

Answer №2

To validate that at least one element is present in the array and the function requires a boolean return value, you can utilize the some method.

The some() method checks if there is at least one element in the array that satisfies the condition specified by the provided function. It then returns a Boolean value.

const selectedFilters = {"color":["Red","Blue"],"type":["Shirt"],"size":["M"]}
const items = [{"name":"Item 1","filters":{"color":["Red","Blue","Black"],"type":["Shirt"],"size":["M"]}},{"name":"Item 2","filters":{"color":["Red"],"type":["Pants"],"size":["M"]}}]

const filterItems = (items, selectedFilters) => {
  const filterKeys = Object.keys(selectedFilters);
  return items.filter(item => {
    return filterKeys.every(key => {
      return selectedFilters[key].some(filterWord => {   //Utilize some method
        return item.filters[key].includes(filterWord);   //Return a boolean value
      });
    })
  });
};

var result = filterItems(items, selectedFilters);
console.log(result);

Condensed version:

const selectedFilters = {"color":["Red","Blue"],"type":["Shirt"],"size":["M"]};

const items = [{"name":"Item 1","filters":{"color":["Red","Blue","Black"],"type":["Shirt"],"size":["M"]}},{"name":"Item 2","filters":{"color":["Red"],"type":["Pants"],"size":["M"]}}];

const filterItems = (items, selectedFilters) => {
  const fkeys = Object.keys(selectedFilters);
  return items.filter(i => fkeys.every(k => selectedFilters[k].some(o => i.filters[k].includes(o))));
};

const result = filterItems(items, selectedFilters);
console.log(result);

Answer №3

If you're looking to tackle this issue, the Array.filter() function is your best friend. Check out this simple yet powerful solution below:

Array.prototype.diff = function(arr2) {
    var ret = [];
    for(var i in this) {   
        if(arr2.indexOf(this[i]) > -1){
            ret.push(this[i]);
        }
    }
    return ret;
};

var filteredArr = items.filter(function (el) {
  return el.filters.color.diff(selectedFilters.color).length > 0 &&
         el.filters.type.diff(selectedFilters.type).length > 0 &&
         el.filters.size.diff(selectedFilters.size).length > 0
});

Check out this working example for reference:

Keep in mind: feel free to adjust the AND / OR condition based on your specific needs.

Answer №4

There are several ways to tackle this issue. For instance, your approach is correct, but we must eliminate the curly brackets {} within each callback function like so:

filterWord => item.filters[key].includes(filterWord)

Another possibility is to transform the selectedFilters into a filterValues array by utilizing the flat() method. This function generates a new array by recursively concatenating all sub-array elements. We then extract the filters from each item and convert them into an itemFilters array using the flat() method once again. Next, we attempt to match them with the filterValues array by combining the every() and includes() methods. These methods assess whether all elements in one array include the elements from another filter array.

The third approach closely resembles your solution. Here, we extract the keys from the selectedFilters and store them in a types array. Subsequently, for each type, we invoke the some() method in conjunction with the includes() method to determine if at least one element in the array is present in items.filters[type].

Below is the implementation:

const selectedFilters = {
    color: ['Red', 'Blue'],
    type: ['Shirt'],
    size: ['M']
};

const items = [
    {
        name: 'Item 1',
        filters: {
            color: ['Red', 'Blue', 'Black'],
            type: ['Shirt'],
            size: ['M']
        }
    },
    {
        name: 'Item 2',
        filters: {
            color: ['Red'],
            type: ['Pants'],
            size: ['M']
        }
    },
    {
        name: 'Item 3',
        filters: {
            color: ['Green', 'Blue', 'Red'],
            type: ['Shirt'],
            size: ['S']
        }
    },
    {
        name: 'Item 4',
        filters: {
            color: ['Red', 'Blue'],
            type: ['Shirt'],
            size: ['M']
        }
    },
};

const filterItems = (items, selectedFilters) => {
    const filterKeys = Object.keys(selectedFilters);
    
    return items.filter(item => {
        return filterKeys.every(key => {
            // Ignore empty filters
            if (!selectedFilters[key].length) {
                return true;
            }
            return selectedFilters[key].every(filterWord => item.filters[key].includes(filterWord));
        });
    });
};

const results = filterItems(items, selectedFilters);

console.log('Your option: ');
results.forEach(function (item, key) {
console.log('Name: ', item.name);
});

const filterValues = Object.values(selectedFilters).flat();
const results2 = items.filter(({filters}) => {
    const itemFilters = Object.values(filters).flat();
    return filterValues.every(filter => itemFilters.includes(filter));
})

console.log('Second option: ');
results2.forEach(function (item, key) {
console.log('Name: ', item.name);
});
 

const types = Object.keys(selectedFilters);
const results3 = items.filter(
    item => types.every(
        type => selectedFilters[type].some(
            filter => item.filters[type].includes(filter)
      )
    )
);

console.log('Third option: ');
results3.forEach(function (item, key) {
console.log('Name: ', item.name);
});

Answer №5

checkFilters = (data)=>{
    let result = true;
    for(item in data) {
            if(item == 'filters') {
                let filterObj = data[item];  
                for(filterKey in filterObj) {
                    for(selectedFilterKey in selectedFilters) {         
                        if(selectedFilterKey == filterKey) {
                            selectedFilters[selectedFilterKey].forEach(value=>{
                                 if(!filterObj[filterKey].includes(value)){
                                    result = false;
                                }
                            })
                        }
                    }
                }
            }
        }
    return result;
}
items.filter((data,index,arr)=> checkFilters(data))

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

Transforming a relation by breaking down an array to output one row for each entry in the array

If we have a table defined as shown below: CREATE TABLE test_values(name TEXT, values INTEGER[]); ...with the following values provided: | name | values | +-------+---------+ | hello | {1,2,3} | | world | {4,5,6} | The goal is to create a query that wi ...

Iterate over JSON elements beginning with a specific pattern

What is the best way to iterate through JSON objects that specifically start with a certain format? For example, if we have a JSON structure like this: { "END": true, "Lines": "End Reached", "term0": { "PrincipalTranslations": { // nest ...

If I deselect an item, the "check all" option does not become deselected

I recently designed a page that displays all the weekdays and dates from Monday to Sunday. I added a feature where users can check all the weekdays with a single click, and uncheck them with another click. However, I encountered an issue where unchecking a ...

Implement a dynamic table in real-time with jQuery AJAX by fetching data from JSON or HTML files

Hey @SOF, I'm trying to add an auto-update feature to my school grades webpage using jquery and ajax to refresh the data when new information is available. I also want to create a "single view" for classes. The challenge I'm facing is getting t ...

Is there a way to sort a table using a dropdown menu selection as a filter?

I am currently working on a project that involves a table with three columns, which are typically populated from a SQL database. My goal is to filter the third column based on the value selected from a dropdown menu. I came across a helpful tutorial on W3 ...

Transforming varied JavaScript objects into a serial form

In my application, there is a concept of an interface along with multiple objects that implement this interface in various ways. These objects are created using different factory methods, with the potential for more factories to be added as the application ...

Retrieve the concealed division element's HTML content along with its formatting

Help needed with appending a hidden div with its styles intact. Despite using the code provided below, the appended div does not retain its styles. Any suggestions for an alternative method? var warningMessage = $('#warningDiv').html() fun ...

Different ways to analyze elements from 2 arrays to hone in on specific values

I'm really struggling to solve this issue. I have two arrays - one for cars and the other for active filters. The cars array consists of HTML li tags with attributes like car type, number of seats, price, etc. On the other hand, the active_filters arr ...

"Switching to the active tab in Bootstrap has been updated

Using Bootstrap, I have implemented this tab: <ul class="nav nav-tabs" id="feedtab"> <li class="active"><a href="#atlass" data-toggle="tab">Atlass</a></li> <li><a href="#avi" data-toggle="tab">Aviation</a&g ...

What is the best way to save the output of an asynchronous (AJAX) function in a variable?

This isn't a repeat query. I'm seeking assistance in locating a technical solution that hasn't been covered in the post How do I return the response from an asynchronous call? If .then() doesn't resolve the Promise, how can I pinpoint ...

Utilizing dynamic meta tags in React JS with a PHP backend and Redux integration

Adding dynamic meta data like title, description, og_image, etc. in reactJs can be a bit complex. I've tried using the react-meta-tags package which changes the title and updates the meta data visible in my browser Inspector. However, when sharing on ...

How to format numbers in JavaScript post calculations

Struggling to find a solution to format calculation results with commas for thousand separators (e.g., 10,000). After implementing the .toLocaleString('en-US', {maximumFractionDigits:1}); method to format numbers in the output, I encountered unex ...

The Firebase function that reloads the auth currentUser is not refreshing properly within a Vue component

My function for updating the profile URL using the reload method is not reflecting changes in my computed property. Computed Property computed: { photoUrl: function() { return firebase.auth().currentUser.photoURL; }, } Function onFileC ...

Activate a drop-down feature to refresh the page with a link attached

When I click on a different language, the drop down does not change to that specific language. My code was functioning properly until I added an href attribute to it. Here, you can see my JavaScript function which handles the language selection logic: $(d ...

How can you implement a bootstrap navigation bar in a vue.js project?

I have encountered a problem with using html in my vue project. Despite following the documentation, it seems that the html is not working properly. I am unsure if this issue could be related to the import of popper.js. I have checked my code and I believe ...

JavaScript syntax issue detected, semicolon missing

I've encountered an issue with a form that contains potential errors defined in PHP. To dynamically change the form action based on the presence of errors, I have incorporated JavaScript into the process. The PHP error variable, $errors, has been conv ...

Utilizing a Chrome profile is ineffective in WebdriverIO

Instead of dealing with signing in every time, I prefer pre-signing in on my profile. Even though I am using the code below, it's still not loading in the specified profile. What can I do to resolve this issue? const browser = await remote({ capabi ...

verifying if checkbox is selected using a while loop in PHP

Help Needed: I am currently trying to loop through some code, but I'm struggling with checking checkboxes using PHP. Could someone please review my code and provide guidance on what needs to be added? Any assistance would be greatly appreciated. Thank ...

Guide on subscribing to an object from a service in Angular 2/5

I am facing an issue where I need to update my property component with data received from the server. In the Service, I have implemented something like this: private events: Event[] = []; eventChanged = new Subject<any>(); // Edit: added an observa ...

Guide on generating and inserting numerous dynamic form sections into a MySQL database

I am looking to create dynamic text fields that will capture information such as name, surname, age, and gender. I want to have a button labeled "add new user" that will allow me to add a new row for entering this information. The reason for needing it dyn ...