Reputation: 327
I have an Array
of Objects
.
Each array of Objects contains an array items
and each item in this array is an Object containing an array category
:
var obj = [
// first object
{
label: 'Label 1',
// first items
items: [
{
id: 1,
itemName: 'Item Name 1',
img: 'imgs/path-to1.jpeg',
sizes: [],
colors: [],
// first category
category: [
'I',
'E',
'M'
],
defaultChoices: {}
},
{
id: 2,
itemName: 'Item Name 2',
img: 'imgs/path-to2.jpeg',
sizes: [],
colors: [],
// second category
category: [
'I',
'E'
],
defaultChoices: {}
},
{
id: 3,
itemName: 'Item Name 3',
img: 'imgs/path-to3.jpeg',
sizes: [],
colors: [],
// third category
category: [
'I'
],
defaultChoices: {}
},
]
},
// second object
{
label: 'Label 2',
// second items
items: [
{
id: 7,
itemName: 'Item Name 7',
img: 'imgs/path-to7.jpeg',
sizes: [],
colors: [],
// fourth category
category: [
'I',
'M'
],
defaultChoices: {}
},
...
just to make the things clearer, a typical direct access to category
would be performed this way: obj[0].items[0].category
.
From the frontend of the app, the user, based on her choices, can send to the application one of the following arrays:
['I']
;['E']
;['M']
;['I','E']
;['I','M']
;['E','M']
;['I','E','M']
;Then, the application should return the obj array filtered: if, for example, the user sent ['I']
, the array should contain any objects where category contains 'I'. If the user sent ['E','M']
, the array should contain any object where category contains ['E','M']
(no matter if category is ['E','M','I']
), and so on.
I red a lot of docs about the JS filter
function but I was not able to develop one function that, given the user array, can return a new array as result of filtering obj
. I found dozen of docs with non-real-life examples like this one:
var hs = [
{name: 'Batman', franchise: 'DC'},
{name: 'Ironman', franchise: 'Marvel'}
];
var marvels = heroes.filter(function(h) {
return hs.franchise == 'Marvel';
});
Any help is appreciated.
[UPDATE] I add a more realistic data sample, sorry for not providing it before: https://drive.google.com/open?id=1sdRx6sQ-cnRXJ8YCe4QH2Sy5fa5mopYW
Upvotes: 3
Views: 2114
Reputation: 4226
This solution uses four Array methods to filter the obj
array: .filter
, .some
, .every
, and .includes
.
// __Simplified version of the 'obj' array__
var obj = [
{
label: '1',
items: [
{id:1, category:['I','E','M']},
{id:2, category:['I','E'] },
{id:3, category:['I']}
]
},
{
label: '2',
items: [
{ id:7, category: ['I','M']}
]
}
];
// __The filter function__
// (Takes an array of user input, and filters the global
// `obj` array to return a new array)
function filterObj(inputArray){
const filtered = obj.filter( object => // Keep the object if...
object.items.some( item => // some item in the object passes this test:
inputArray.every( value => // For every value in the input array...
item.category.includes(value) // the item's 'category' array includes value
)
)
);
return filtered;
}
// __Testing function__
// (Calls `filterObj` on a test array and logs the results)
function test(input){
console.log(`Testing this input: ${ input }`);
console.log("Obects having `some` item where `every` value in the input array is `included`:");
filterObj(input).forEach( matchingObject => { console.log(matchingObject.label); });
console.log("");
}
// __Tests__
test(['I','M']);
test(['I','E']);
(Note: The output is according to the OP's original specification that "if, for example, the user sent ['I'], the array should contain any objects where category contains 'I' ")
Upvotes: 1
Reputation: 368
If you want to filter by category, which the number of object
in the array is remained unchanged(even all items in that object are filter out and there is no item in the object), then it should be what you want:
var obj = [ // I removed some unnecessary params to make it clear, which shouldn't affect any
{
label: 'Label 1',
items: [
{
id: 1,
category: ['I', 'E', 'M'],
},
{
id: 2,
category: ['I', 'E'],
},
{
id: 3,
category: ['I'],
},
]
},
{
label: 'Label 2',
items: [
{
id: 7,
category: ['I', 'M'],
},
]}
]
function filterByCategory(obj, categories) {
return obj.map( o => ({
...o, // copy everything(i.e. label, items)
items: o.items.filter(item => // modify items in the obj
categories.some(c => item.category && item.category.includes(c)) // keep item if some categories are in item
)
}))
}
const filteredObj = filterByCategory(obj, ['I', 'E'])
console.log(filteredObj)
If you want to further filter out the object that there is no item, you can add
.filter(o => o.items.length)
at the end of filterByCategory
.
Live Example:
var data = [ { label: 'Label 1', items: [{ id: 1, itemName: 'Item Name 1', img: 'imgs/path-to1.jpeg', sizes: [], colors: [], category: [ 'I', 'E', 'M' ], defaultChoices: {} }, { id: 2, itemName: 'Item Name 2', img: 'imgs/path-to2.jpeg', sizes: [], colors: [], category: [ 'I', 'E' ], defaultChoices: {} }, { id: 3, itemName: 'Item Name 3', img: 'imgs/path-to3.jpeg', sizes: [], colors: [], category: [ 'I' ], defaultChoices: {} }, ] }, { label: 'Label 2', items: [{ id: 7, itemName: 'Item Name 7', img: 'imgs/path-to7.jpeg', sizes: [], colors: [], category: [ 'I', 'M' ], defaultChoices: {} }] } ];
function filterByCategory(data, category) {
return data.map(obj => {
return { ...obj,
"items": obj.items.filter(item =>
category.some(value => item.category && item.category.includes(value))
)
};
});
}
console.log(filterByCategory(data, ['E', 'M']));
Upvotes: 3
Reputation: 14730
This code iterates through all Objects and items and creates a new Object with only items that have the specified Categories. A more detailed description of the the Code is in the Comments:
// function where you enter the Objects and the Categories you want to filter
function getFilterObjectItems(objs, categories){
// Filtered Objects
return objs.map(function(obj) {
// Creates a new Item
var newObject = {label: obj.label, items:[]};
//iterate through all items in an Object looking for items with matching Category
obj.items.forEach(function(item){
// if one category entry matches add item to new Object
// the "some" function returns "true" or "false" if one item matches the critieria
if(item && item.category && item.category.some && item.category.some(cat => searchedCAT.indexOf(cat)>-1)){
// the original item will be added to the new item ist
newObject.items.push(item);
}
});
return newObject;
})
// filters all New Objects that don't have items
.filter(newObject => newObject.items.length>0);
}
// DATA from the Question
var obj = [
// first object
{
label: 'Label 1',
// first items
items: [
{
id: 1,
itemName: 'Item Name 1',
img: 'imgs/path-to1.jpeg',
sizes: [],
colors: [],
// first category
category: [
'I',
'E',
'M'
],
defaultChoices: {}
},
{
id: 2,
itemName: 'Item Name 2',
img: 'imgs/path-to2.jpeg',
sizes: [],
colors: [],
// second category
category: [
'I',
'E'
],
defaultChoices: {}
},
{
id: 3,
itemName: 'Item Name 3',
img: 'imgs/path-to3.jpeg',
sizes: [],
colors: [],
// third category
category: [
'I'
],
defaultChoices: {}
},
]
},]
// search Categories
var searchedCAT = ['I'];
// Calling the Function
console.info(getFilterObjectItems(obj, searchedCAT));
Upvotes: 2
Reputation: 92
const UserChoice = ['E', 'X'];
const filtered = obj.filter(o => {
const filteredItems = o.items.filter(item =>
item.category.map(c => UserChoice.includes(c)).includes(true)
);
if (filteredItems.length > 0) {
o.items = filteredItems;
return o;
}
});
"filtered" will have your filtered obj
Upvotes: 2