【问题标题】:Filtering array of objects by searching nested object properties通过搜索嵌套对象属性过滤对象数组
【发布时间】:2018-01-16 10:05:27
【问题描述】:

我有一个对象数组,我想通过将嵌套属性与搜索词进行比较来过滤它们。

例如:

 var array = [
      {category: 'Business'
       users: [
                {name: 'Sally'
                 tags: [{tag: 'accounting'}, {tag: 'marketing'},...]
                },
                {name: 'Bob'
                 tags: [{tag: 'sales'}, {tag: 'accounting'},...]
                }...
              ]
       },
       {category: 'Heritage'
        users: [
                 {name: 'Linda'
                  tags: [{tag: 'Italy'}, {tag: 'Macedonia'},...]
                 },
                 {name: 'George'
                  tags: [{tag: 'South Africa'}, {tag: 'Chile'},...]
                 },...
               ]
       },...
    [

本质上,我想通过搜索项过滤对象的基本数组,其中包括嵌套对象 2 个数组中标签属性字符串中的字符。

所以搜索“市场”会导致

[
  {category: 'Business'
   users: [
            {name: 'Sally'
             tags: [{tag: 'accounting'}, {tag: 'marketing'},...]
            },
            {name: 'Bob'
             tags: [{tag: 'sales'}, {tag: 'accounting'},...]
            }...
          ]
   }
]

谢谢。

【问题讨论】:

    标签: javascript arrays object filter


    【解决方案1】:

    您可以使用Array#filter 通过Array#some 查看嵌套数组。

    如果在嵌套数组中找到标记,则迭代停止并将结果返回给过滤器回调。

    var array = [{ category: 'Business', users: [{ name: 'Sally', tags: [{ tag: 'accounting' }, { tag: 'marketing' }] }, { name: 'Bob', tags: [{ tag: 'sales' }, { tag: 'accounting' }] }] }, { category: 'Heritage', users: [{ name: 'Linda', tags: [{ tag: 'Italy' }, { tag: 'Macedonia' }] }, { name: 'George', tags: [{ tag: 'South Africa' }, { tag: 'Chile' }] }] }],
        tag = 'marketing',
        result = array.filter(a => a.users.some(u => u.tags.some(t => t.tag.includes(tag))));
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

    • 如果我想比较两个值?
    【解决方案2】:

    使用Array.prototype.some()函数的解决方案:

    var arr = [{ category: 'Business', users: [{ name: 'Sally', tags: [{ tag: 'accounting' }, { tag: 'marketing' }] }, { name: 'Bob', tags: [{ tag: 'sales' }, { tag: 'accounting' }] }] }, { category: 'Heritage', users: [{ name: 'Linda', tags: [{ tag: 'Italy' }, { tag: 'Macedonia' }] }, { name: 'George', tags: [{ tag: 'South Africa' }, { tag: 'Chile' }] }] }], 
        search_key = 'market',
        result = [];
        
    arr.forEach(function(o){
        if (o.users.some(function(v){
            return v.tags.some(function(i){ return i.tag.indexOf(search_key) !== -1; });
        })) {
            result.push(o);
        }
    });
    
    console.log(result);

    【讨论】:

    • 这是一个很好的答案罗马,谢谢。我刚刚接受了 Nina 的,因为首先添加了她的并且更简洁一些。干得好。
    【解决方案3】:

    试试这个:

    function search(term){
    return
        Array.filter(array,function(item){
           return JSON.stringify(obj).indexOf(term)!=-1;
        });
    }
    

    所以:

    console.log(search('market'));
    

    希望对你有帮助:)

    【讨论】:

    • 这也会搜索键,所以如果你搜索“tag”,你会发现每个对象都匹配。
    【解决方案4】:

    concatAllconcatMap 定义取自 http://reactivex.io/learnrx/

    Array.prototype.concatAll = function() {
        var results = [];
        this.forEach(function(subArray) {
            results.push.apply(results, subArray);
        });
    
        return results;
    };
    
    Array.prototype.concatMap = function(projectionFunctionThatReturnsArray) {
        return this.
            map(function(item) {
                return projectionFunctionThatReturnsArray(item);
            }).
            // apply the concatAll function to flatten the two-dimensional array
            concatAll();
    };
    
    function filterByTags(keyword) {
      return array.filter(function (item) {
        var allTags = item.users.concatMap(function (user) {
          return user.tags.map(function (tag) {
            return tag.tag;
          });
        });
    
        return allTags.some(function (tag) {
          return tag.indexOf(keyword) > -1;
        });
      });
    }
    
    console.log(filterByTags('market'));
    

    当然,您可以内联 allTags 变量以获得更简洁。

    应用于初始数组的filter 将返回其标签包含所提供关键字的用户的所有项目。策略是构建用户标签的扁平化版本并在其上应用some

    【讨论】:

      【解决方案5】:

      你可以像这样使用array.filter

      function getFiltered(val) {
           return array.filter(category == val);
      }
      

      此函数将返回一个新的数组实例,仅使用您作为 val 参数传递的 category 键。

      【讨论】:

        【解决方案6】:

        注意:我对此采取了类似捷径的方法,主要是为了提供不同的视角来解决问题。

        您可以创建 users 属性的 json 字符串并在其中搜索,而不是深入搜索主 array 下的属性和数组。因此,我创建了一个新属性 usersString,该属性临时存储针对 users 属性的值的 JSON 字符串。

        item.usersString = JSON.stringify(item.users);
        

        现在,这不是一个完美的实现,但它几乎总是可以工作的。此外,如果您将此属性存储在浏览器中(而不将其存储回数据库),并在每次用户搜索时使用它来快速搜索,我认为它会比深度搜索整个数组更高效。

        var array = [{
            category: 'Business',
            users: [{
                name: 'Sally',
                tags: [{
                  tag: 'accounting'
                }, {
                  tag: 'marketing'
                }]
              },
              {
                name: 'Bob',
                tags: [{
                  tag: 'sales'
                }, {
                  tag: 'accounting'
                }]
              }
            ]
          },
          {
            category: 'Heritage',
            users: [{
                name: 'Linda',
                tags: [{
                  tag: 'Italy'
                }, {
                  tag: 'Macedonia'
                }]
              },
              {
                name: 'George',
                tags: [{
                  tag: 'South Africa'
                }, {
                  tag: 'Chile'
                }]
              }
            ]
          }
        ];
        
        var key = "market";
        
        // Convert the users property into a string - so that it works as a quick search target.
        array.forEach(function(item) {
          item.usersString = JSON.stringify(item.users);
        });
        
        
        var filteredItems = array.filter(function(item) {
          return item.usersString.toLowerCase().indexOf(key.toLowerCase()) >= 0;
        });
        
        // Delete the usersString property - if required.
        filteredItems.forEach(function(item) {
          item.usersString = undefined;
          // Or,
          // delete item.usersString;
        })
        
        console.log(filteredItems);

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-09-17
          • 1970-01-01
          • 1970-01-01
          • 2021-10-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-05-29
          相关资源
          最近更新 更多