【问题标题】:Filter values of multiple properties with an array of values使用一组值过滤多个属性的值
【发布时间】:2015-09-14 20:54:20
【问题描述】:

所以我真的很想复制我以前的failed question,因为我真的无法正确解释自己,因此没有得到答案(也没有真正解决我的问题)。

有 JSON:

[
  {
    "id": 2,
    "name": "Google",
    "country": "Sweden"
  },
  {
    "id": 3,
    "name": "Google",
    "country": "USA"
  },
  {
    "id": 9,
    "name": "Google",
    "country": "Ukraine"
  },
  {
    "id": 10,
    "name": "Bing",
    "country": "Sweden"
  }
]

我想我之前没有做的是发布我到目前为止的内容并更好地解释我需要什么。这就是我现在拥有的:

 $scope.loadSearchEngines = function ($query) {
     return $http.get('search-engines.json', {cache: true}).then(function (response) {
         var tags = response.data;
         return tags.filter(function (tag) {
             return tag.name.toLowerCase().indexOf($query.toLowerCase()) != -1;
         });
     });
 };

这个过滤器限制我只能搜索 name 属性,而理想情况下我想搜索 any 属性(或者是所有属性),我想要过滤器使用一组参数,以便每个单词单独查看对象中的每个属性并找到匹配项。

在上一篇文章中,有人为它发布了一个 for 循环,但这正是我想要避免的那种不直观的事情。 我知道我想要的结果是什么,但我只是想不出一种方法(lodash/underscore 似乎几乎做了这样的事情,但我认为某处缺少一些东西,或者我真的不擅长理解文档)。

例子:

如果我写“google sweden”,它只会显示 1 个结果,如果我写“sweden”,它将显示来自 google 的结果和来自 bing 的结果。 如果我写“in”,我猜它应该显示“bING”和谷歌“ukraINe”。

起初这似乎没有那么麻烦,但我无法使用过滤器真正解决这个问题。我真的没有任何想法要发布,因为它们非常糟糕,这对我来说真的是一个灰色地带。

【问题讨论】:

  • 您要在对象的所有值中搜索关键字?

标签: javascript json underscore.js filtering lodash


【解决方案1】:

版本 A 将整个数据集的结果调整为遍历搜索词的所需集。

var data = [{
        "id": 2,
        "name": "Google",
        "country": "Sweden"
    }, {
        "id": 3,
        "name": "Google",
        "country": "USA"
    }, {
        "id": 9,
        "name": "Google",
        "country": "Ukraine"
    }, {
        "id": 10,
        "name": "Bing",
        "country": "Sweden"
    }];

function search(s) {
    var searchA = s.split(' ').map(function (a) { return a.toLowerCase(); });
    var result = JSON.parse(JSON.stringify(data));
    searchA.forEach(function (a) {
        result = result.reduce(function (res, el) {
            var i;
            for (i in el) {
                if (~('' + el[i]).toLowerCase().indexOf(a)) {
                    res.push(el);
                    break;
                }
            }
            return res;
        }, []);
    });
    return result;
}
out('search for \'google sweden\'\n' + JSON.stringify(search('google sweden'), null, 4), true);
out('search for \'bing\'\n' + JSON.stringify(search('bing'), null, 4), true);
out('search for \'IN\'\n' + JSON.stringify(search('IN'), null, 4), true);
out('search for \'x\'\n' + JSON.stringify(search('x'), null, 4), true);

function out(s, pre) {
    var descriptionNode = document.createElement('div');
    if (pre) {
        var preNode = document.createElement('pre');
        preNode.innerHTML = s + '<br>';
        descriptionNode.appendChild(preNode);
    } else {
        descriptionNode.innerHTML = s + '<br>';
    }
    document.getElementById('out0').appendChild(descriptionNode);
}
&lt;div id="out0"&gt;&lt;/div&gt;

B 版采用不同的方法。在这里我收集符合要求的对象。

var data = [{
        "id": 2,
        "name": "Google",
        "country": "Sweden"
    }, {
        "id": 3,
        "name": "Google",
        "country": "USA"
    }, {
        "id": 9,
        "name": "Google",
        "country": "Ukraine"
    }, {
        "id": 10,
        "name": "Bing",
        "country": "Sweden"
    }];

function search(s) {
    var searchA = s.split(' ').map(function (a) { return a.toLowerCase(); });
    return data.reduce(function (res, el) {
        var i, found = 0;
        for (i in el) {
            found += searchA.some(function (a) {
                return ~('' + el[i]).toLowerCase().indexOf(a);
            });
        }
        found === searchA.length && res.push(el);
        return res;
    }, []);
}

out('search for \'google sweden\'\n' + JSON.stringify(search('google sweden'), null, 4), true);
out('search for \'bing\'\n' + JSON.stringify(search('bing'), null, 4), true);
out('search for \'IN\'\n' + JSON.stringify(search('IN'), null, 4), true);
out('search for \'x\'\n' + JSON.stringify(search('x'), null, 4), true);

function out(s, pre) {
    var descriptionNode = document.createElement('div');
    if (pre) {
        var preNode = document.createElement('pre');
        preNode.innerHTML = s + '<br>';
        descriptionNode.appendChild(preNode);
    } else {
        descriptionNode.innerHTML = s + '<br>';
    }
    document.getElementById('out').appendChild(descriptionNode);
}
&lt;div id="out"&gt;&lt;/div&gt;

【讨论】:

  • 与另一个答案相同,如果您输入 2 个单词,它应该匹配它们,否则如果我有 20 个不同的 bings 和 20 个不同的 google,它将显示所有这些,这就是我想避免。输入“google sweden”应该只显示 1 个结果。
  • 现在你得到一个匹配所有参数的搜索(AND而不是OR)。
  • 呃,这正是我需要的。如果您有时间并且愿意解释 for 循环和 found === searchA.length &amp;&amp; res.push(el); 部分的工作原理,那也很棒(归根结底,学习这样做并自己理解它就是我在这里的原因)。
  • 我猜some 的使用和~('' + el[i]).toLowerCase().indexOf(a) 这一行对我来说是陌生的,我从未见过/使用过这样的东西。
  • found === searchA.length &amp;&amp; res.push(el); 读作if (found === searchA.length) { res.push(el); }。比较检查所需单词的长度是否等于找到的单词。 Array.some() 正在返回 true,如果回调返回 true(可以是比较或其他)。 ~('' + el[i]).toLowerCase().indexOf(a)el[i] 转换为字符串,应用小写并在内部查找a 的索引。波浪号按位不应用于该值,因此-1(不在字符串中)计算为false(= ~-1 = 0),所有其他值计算为true,此处使用。
【解决方案2】:

从问题看来,您好像要过滤一个列表,其中每个项目中的值包含每个关键字:

    var keywords = ['Google', 'Sweden'];

    var result = _.filter(data, function(item){
        return _.every(keywords, function(keyword){
            return _.some(item, function(value){
                return _.isString(value) && value.indexOf(keyword) != -1;
            })
        });
    });

【讨论】:

  • 这太棒了!我进行了 1 处更改以使其更好。如果将字符串规范化为大写,则搜索不区分大小写。 value.toUpperCase().indexOf(keyword.toUpperCase()) != -1;
【解决方案3】:

也许是这样的(注意,可能不是最有效的)。不处理小写,但添加起来很简单。

http://jsfiddle.net/W4QfJ/520/

var stuff = [
  {
    "id": 2,
    "name": "Google",
    "country": "Sweden"
  },
  {
    "id": 3,
    "name": "Google",
    "country": "USA"
  },
  {
    "id": 9,
    "name": "Google",
    "country": "Ukraine"
  },
  {
    "id": 10,
    "name": "Bing",
    "country": "Sweden"
  }
];

var searchTerm = 'Google Sweden';
var searchTermArr = searchTerm.split(' ');
var results = [];
var obj;
searchTermArr.forEach(function (val, index, arr) {
    obj = _(stuff)
      .filter(function (s) {
          return JSON.stringify(s).indexOf(val) > -1;
      }).value();
    results = results.concat(obj);
});

console.log(_.unique(results));

【讨论】:

  • 这里的问题仍然是“google sweden”应该只显示同时匹配google和sweden的答案,所以它应该只显示一个结果。
猜你喜欢
  • 1970-01-01
  • 2020-01-21
  • 1970-01-01
  • 1970-01-01
  • 2015-02-11
  • 1970-01-01
  • 2017-11-03
  • 1970-01-01
  • 2020-04-21
相关资源
最近更新 更多