Write a function called excludeItems where the first input argument represents your dataset (list of objects) and the second input represents the key value properties you want to exclude (list of objects) and returns the list excluding the key value properties specified in your second argument.
For Example
const items = [
{ color: 'red', type: 'tv', age: 18 },
{ color: 'red', type: 'phone', age: 20 },
{ color: 'silver', type: 'tv', age: 18 },
{ color: 'silver', type: 'phone', age: 20 }
];
const excludes = [
{ k: 'color', v: 'red' },
{ k: 'color', v: 'blue' },
{ k: 'type', v: 'phone' },
];
expectedOutput = [
{ type: 'tv', age: 18 },
{ age: 20 },
{ color: 'silver', type: 'tv', age: 18 },
{ color: 'silver', age: 20 }
];
I came up with two similar solutions, where I think the second one is slightly better as you don't have to iterate over the values list to check if the value from the original object exists there.
I would like to understand if there is an even better approach than this.
// Option 1
function excludeItems(items, excludes) {
let exclusionMap = {};
let results = [];
excludes.forEach(item => {
if(!exclusionMap[item.k])
exclusionMap[item.k] = [];
let itemDoesNotExist = exclusionMap[item.k].indexOf(item.v) === -1;
if(itemDoesNotExist) {
exclusionMap[item.k].push(item.v);
}
})
results = items.map(item => {
for(let key in exclusionMap) {
let exclusionValues = exclusionMap[key];
if(item[key]) {
let itemValue = item[key]
let itemValueIndexInExclusionValue = exclusionValues.indexOf(itemValue);
if(itemValueIndexInExclusionValue !== -1) {
delete item[key];
}
}
}
return item;
});
return results;
}
// Option 2
function excludeItems(items, excludes) {
let exclusionMap = {};
let results = [...items];
excludes.forEach(item => {
exclusionMap[item.k '_' item.v] = true;
})
results.map(item => {
for(const key in exclusionMap) {
const k = key.split('_')[0]; // type
const v = key.split('_')[1]; // phone
if(v == item[k]) {
delete item[k]
}
}
return item;
})
return results;
}
Thanks
CodePudding user response:
You could filter the entries and rebuild the objects while mapping a new array.
function excludeItems(items, excludes) {
return items.map(o => Object.fromEntries(Object
.entries(o)
.filter(([k, v]) => !excludes.some(q => q.k === k && q.v === v))
));
}
const
items = [{ color: 'red', type: 'tv', age: 18 }, { color: 'red', type: 'phone', age: 20 }, { color: 'silver', type: 'tv', age: 18 }, { color: 'silver', type: 'phone', age: 20 }],
excludes = [{ k: 'color', v: 'red' }, { k: 'color', v: 'blue' }, { k: 'type', v: 'phone' }];
console.log(excludeItems(items, excludes));
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you do not mind the types, you could take an shorter approach with an object.
function excludeItems(items, excludes) {
const pairs = Object.fromEntries(excludes.map(({ k, v }) => [`${k}|${v}`, true]));
return items.map(o => Object.fromEntries(Object
.entries(o)
.filter(([k, v]) => !pairs[`${k}|${v}`])
));
}
const
items = [{ color: 'red', type: 'tv', age: 18 }, { color: 'red', type: 'phone', age: 20 }, { color: 'silver', type: 'tv', age: 18 }, { color: 'silver', type: 'phone', age: 20 }],
excludes = [{ k: 'color', v: 'red' }, { k: 'color', v: 'blue' }, { k: 'type', v: 'phone' }];
console.log(excludeItems(items, excludes));
.as-console-wrapper { max-height: 100% !important; top: 0; }
CodePudding user response:
Here's a third option, which you can consider as well. It uses Array.filter and Array.forEach, and avoids using a map:
function excludeItems(items, excludes) {
let results = [...items];
excludes.forEach(exclude => {
results = results.filter(item => !(item.hasOwnProperty(exclude.k) && item[exclude.k] === exclude.v));
});
return results;
}
This implementation filters the results array based on the keys and values to exclude. The advantage of using Array.filter is that it provides a clean way to exclude the items, without having to modify the original array.
CodePudding user response:
I came up with a simple solution with comments that is easy to understand and follow
function excludeItems(items, excludes) {
let exclusionMap = {};
// exclusionMap will be represented as
// { type: ['red', etc...]}
excludes.forEach(item => {
if(!exclusionMap[item.k]) {
exclusionMap[item.k] = [];
}
exclusionMap[item.k].push(item.v);
});
// Filter items
return items.filter(item => {
// Get each object key in item and value independently
for(let key in item) {
// ex: key = color
let itemValue = item[key]; // ex: red
// Check if exclusionMap has that key, if it does, check if the key values contain the value
if(exclusionMap[key] && exclusionMap[key].includes(itemValue)) {
// If so, exclude it
return false;
}
// otherwise don't do anything
}
// return true for all other cases
return true;
});
}