Home > Mobile >  Exclude list of properties from list of objects
Exclude list of properties from list of objects

Time:01-30

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;
  });
}
  • Related