Filter array of objects whose any properties conta

2020-02-23 08:06发布

问题:

I'm wondering what is the cleanest way, better way to filter an array of objects depending on a string keyword. The search has to be made in any properties of the object.

When I type lea I want to go trough all the objects and all their properties to return the objects that contain lea

When I type italy I want to go trough all the objects and all their properties to return the objects that contain italy.

I know there are lot of solutions but so far I just saw some for which you need to specify the property you want to match.

ES6 and lodash are welcome !

  const arrayOfObject = [{
      name: 'Paul',
      country: 'Canada',
    }, {
      name: 'Lea',
      country: 'Italy',
    }, {
      name: 'John',
      country: 'Italy',
    }, ];

    filterByValue(arrayOfObject, 'lea')   // => [{name: 'Lea',country: 'Italy'}]
    filterByValue(arrayOfObject, 'ita')   // => [{name: 'Lea',country: 'Italy'}, {name: 'John',country: 'Italy'}]

回答1:

You could filter it and search just for one occurence of the search string.

Methods used:

  • Array#filter, just for filtering an array with conditions,

  • Object.keys for getting all property names of the object,

  • Array#some for iterating the keys and exit loop if found,

  • String#toLowerCase for getting comparable values,

  • String#includes for checking two string, if one contains the other.

function filterByValue(array, string) {
    return array.filter(o =>
        Object.keys(o).some(k => o[k].toLowerCase().includes(string.toLowerCase())));
}

const arrayOfObject = [{ name: 'Paul', country: 'Canada', }, { name: 'Lea', country: 'Italy', }, { name: 'John', country: 'Italy' }];

console.log(filterByValue(arrayOfObject, 'lea')); // [{name: 'Lea', country: 'Italy'}]
console.log(filterByValue(arrayOfObject, 'ita')); // [{name: 'Lea', country: 'Italy'}, {name: 'John', country: 'Italy'}]
.as-console-wrapper { max-height: 100% !important; top: 0; }



回答2:

Well when we already know that its not going to be a search on an object with methods, we can do the following for saving bit on time complexity :

function filterByValue(array, value) {
  return array.filter((data) =>  JSON.stringify(data).toLowerCase().indexOf(value.toLowerCase()) !== -1);
}


回答3:

Use Object.keys to loop through the properties of the object. Use reduce and filter to make the code more efficient:

 const results = arrayOfObject.filter((obj)=>{
     return Object.keys(obj).reduce((acc, curr)=>{
           return acc || obj[curr].toLowerCase().includes(term);
     }, false);
}); 

Where term is your search term.



回答4:

You can always use array.filter() and then loop through each object and if any of the values match the value you are looking for, return that object.

const arrayOfObject = [{
      name: 'Paul',
      country: 'Canada',
    }, {
      name: 'Lea',
      country: 'Italy',
    }, {
      name: 'John',
      country: 'Italy',
    }, ];
    
let lea = arrayOfObject.filter(function(obj){
  //loop through each object
  for(key in obj){
    //check if object value contains value you are looking for
    if(obj[key].includes('Lea')){
      //add this object to the filtered array
      return obj;
      }
     }
    });
      
console.log(lea);



回答5:

function filterByValue(arrayOfObject,words){
  let reg = new RegExp(words,'i');
  return arrayOfObject.filter((item)=>{
     let flag = false;
     for(prop in item){
       if(reg.test(prop)){
          flag = true;
       }  
     }
     return flag;
  });
}



回答6:

Here's how I would do it using lodash:

const filterByValue = (coll, value) =>
  _.filter(coll, _.flow(
    _.values,
    _.partialRight(_.some, _.method('match', new RegExp(value, 'i')))
  ));

filterByValue(arrayOfObject, 'lea');
filterByValue(arrayOfObject, 'ita');


回答7:

This code checks all the nested values until it finds what it's looking for, then stops and returns true to the "array.filter" for the object it was searching inside(unless it can't find anything - returns false). When true is returned, the object is added to the array that the "array.filter" method returns.

const data = [{
    a: "a",
    b: {
      c: "c",
      d: {
        e: "e",
        f: [
          "g",
          {
            i: "i",
            j: {},
            k: []
          }
        ]
      }
    }
  },
  {
    a: "a",
    b: {
      c: "c",
      d: {
        e: "e",
        f: [
          "g",
          {
            i: "findme",
            j: {},
            k: []
          }
        ]
      }
    }
  },
  {
    a: "a",
    b: {
      c: "c",
      d: {
        e: "e",
        f: [
          "g",
          {
            i: "i",
            j: {},
            k: []
          }
        ]
      }
    }
  }
];

function getState(data: any, inputValue: string, state = false) {
  for (const value of Object.values(data)) {
    if (typeof value === 'object' && value !== null && Object.keys(value).length > 0 && state === false) {
      state = getState(value, inputValue, state);
    } else {
      if (state === false) {
        state = JSON.stringify(value).toLowerCase().includes(inputValue.toLowerCase());
      } else {
        return state;
      }
    }
  }
  return state;
}

function filter(data: [], inputValue) {
  return data.filter((element) => getState(element, inputValue));
}

console.log(filter(data, 'findme'));



回答8:

One way would be to use Array#filter, String#toLowerCase and String#indexOf like below.

const arrayOfObject = [{
            name: 'Paul',
            country: 'Canada',
        }, {
            name: 'Lea',
            country: 'Italy',
        }, {
            name: 'John',
            country: 'Italy',
        }];

        function filterByValue(arrayOfObject, term) {
            var ans = arrayOfObject.filter(function(v,i) {
                if(v.name.toLowerCase().indexOf(term) >=0 || v.country.toLowerCase().indexOf(term) >=0) {
                    return true;
                } else false;
            });
            console.log( ans);
        }
        filterByValue(arrayOfObject, 'ita');