【问题标题】:Filter array of objects whose any properties contains a value过滤任何属性都包含值的对象数组
【发布时间】:2017-11-02 22:05:20
【问题描述】:

我想知道根据string keyword 过滤对象数组的最干净、更好的方法是什么。必须在对象的任何属性中进行搜索。

当我输入lea 时,我想遍历所有对象及其所有属性以返回包含lea 的对象

当我输入italy 时,我想遍历所有对象及其所有属性以返回包含italy 的对象。

我知道有很多解决方案,但到目前为止,我只看到了一些您需要指定要匹配的属性的解决方案。

欢迎使用 ES6 和 lodash!

  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'}]

【问题讨论】:

  • 支持现场堆栈 sn-ps 优于 jsfiddle 等非现场服务。

标签: javascript arrays lodash


【解决方案1】:

您可以过滤它并仅搜索一次出现的搜索字符串。

使用的方法:

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; }

【讨论】:

  • 如果其中一个属性不是字符串而是对象,我们可能想使用这个function filterByValue(array, string) { return array.filter(o => { return Object.keys(o).some(k => { if(typeof o[k] === 'string') return o[k].toLowerCase().includes(string.toLowerCase()); }); }); }
  • 您可以在没有if 声明的情况下使用return typeof o[k] === 'string' && o[k].toLowerCase().includes(string.toLowerCase()); 来缩短它
  • 如果值不总是字符串,那么使用String(o[k]) 而不是o[k]。见这里:stackoverflow.com/a/11083415/2110294
  • 另外,最好在乞求中检查参数“string”的类型,比如这个 function filterByValue(array, string) { return typeof string === 'string' && array.filter (o => Object.keys(o).some(k => { return typeof o[k] === 'string' && o[k].toLowerCase().includes(string.toLowerCase()))); }
  • function filterByValue(array, string) { return array.filter(o => Object.keys(o).some(k => o[k].toString().toLowerCase().includes (string.toString().toLowerCase()))); } 细微变化
【解决方案2】:

好吧,当我们已经知道它不会是使用方法搜索对象时,我们可以执行以下操作以节省时间复杂度:

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

【讨论】:

  • 这也会在对象的键上找到搜索关键字,但可能 OP 只想搜索值。
  • 是的,使用正则表达式可以避免这种情况。这里的想法是消除对象键的循环
  • 如何只循环键?你的眼球不能向上看一英寸吗?
  • 这很有帮助。我也希望在这里找到一个例子。对于其他希望有一个很好的例子的人来说,这是我为我的案例编写和工作的内容。 JSON.stringify(terminal).replace(/("\w+":)/g, '').toLowerCase()。这会将"{"myKey":"myValue","myKey2":"myValue2","mySubObject":{"subKey":"subValue"}}" 变成{"myValue","myValue2","subValue"}
  • 这是最好的。
【解决方案3】:

使用 Object.keys 循环遍历对象的属性。使用reduce和filter让代码更高效:

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

term 是您的搜索词。

【讨论】:

  • 太棒了!突出显示搜索条件呢?你能帮我添加相同的标签替换搜索条件吗?类似 '' + term + ''
  • @Vincent Ramdhanie 是否可以在不循环遍历所有对象数组的情况下替换搜索词?
【解决方案4】:

您始终可以使用array.filter(),然后循环遍历每个对象,如果任何值与您要查找的值匹配,则返回该对象。

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】:

    此代码检查所有嵌套值,直到找到它正在寻找的内容,然后为它正在搜索的对象返回 true 到“array.filter”(除非它找不到任何东西 - 返回 false)。返回 true 时,将对象添加到“array.filter”方法返回的数组中。当输入多个关键字时(用逗号和空格隔开),搜索范围会进一步缩小,使用户更容易搜索。

    Stackblitz example

    const data = [
      {
        a: 'aaaaaa',
        b: {
          c: 'c',
          d: {
            e: 'e',
            f: [
              'g',
              {
                i: 'iaaaaaa',
                j: {},
                k: [],
              },
            ],
          },
        },
      },
      {
        a: 'a',
        b: {
          c: 'cccccc',
          d: {
            e: 'e',
            f: [
              'g',
              {
                i: 'icccccc',
                j: {},
                k: [],
              },
            ],
          },
        },
      },
      {
        a: 'a',
        b: {
          c: 'c',
          d: {
            e: 'eeeeee',
            f: [
              'g',
              {
                i: 'ieeeeee',
                j: {},
                k: [],
              },
            ],
          },
        },
      },
    ];
    
    function filterData(data, filterValues) {
      return data.filter((value) => {
        return filterValues.trim().split(', ').every((filterValue) => checkValue(value, filterValue));
      });
    }
    
    function checkValue(value, filterValue) {
      if (typeof value === 'string') {
        return value.toLowerCase().includes(filterValue.toLowerCase());
      } else if (typeof value === 'object' && value !== null && Object.keys(value).length > 0) {
        if (Array.isArray(value)) {
          return value.some((v) => checkValue(v, filterValue));
        } else {
          return Object.values(value).some((v) => checkValue(v, filterValue));
        }
      } else {
        return false;
      }
    }
    
    console.log(filterData(data, 'a, c'));
    console.log(filterData(data, 'a, c, ic'));

    【讨论】:

      【解决方案6】:

      一种方法是使用Array#filterString#toLowerCaseString#indexOf,如下所示。

      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');

      【讨论】:

        【解决方案7】:

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

        【讨论】:

          【解决方案8】:

          下面是我使用 lodash 的方法:

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

          【讨论】:

            【解决方案9】:

            这是上面的一个版本,它通过从对象属性数组派生的值进行过滤。该函数接受对象数组和指定的对象属性键数组。

            // fake ads list with id and img properties
            const ads = [{
              adImg: 'https://test.com/test.png',
              adId: '1'
            }, {
              adImg: 'https://test.com/test.png',
              adId: '2'
            }, {
              adImg: 'https://test.com/test.png',
              adId: '3'
            }, {
              adImg: 'https://test.com/test-2.png',
              adId: '4'
            }, {
              adImg: 'https://test.com/test-2.png',
              adId: '5'
            }, {
              adImg: 'https://test.com/test-3.png',
              adId: '6'
            }, {
              adImg: 'https://test.com/test.png',
              adId: '7'
            }, {
              adImg: 'https://test.com/test-6.png',
              adId: '1'
            }];
            
            // function takes arr of objects and object property
            // convert arr of objects to arr of filter prop values
            const filterUniqueItemsByProp = (arrOfObjects, objPropFilter) => {
              return arrOfObjects.filter((item, i, arr) => {
                return arr.map(prop => prop[objPropFilter]).indexOf(item[objPropFilter]) === i;
              });
            };
            
            const filteredUniqueItemsByProp = filterUniqueItemsByProp(ads, 'adImg');
            
            console.log(filteredUniqueItemsByProp);

            【讨论】:

              猜你喜欢
              • 2021-12-08
              • 2019-10-01
              • 2019-05-04
              • 1970-01-01
              • 1970-01-01
              • 2019-07-30
              • 1970-01-01
              • 2022-08-18
              • 1970-01-01
              相关资源
              最近更新 更多