Reputation:
So I really would like to make a duplicate out of my previous failed question because I wasn't really able to explain myself properly and thus didn't get the answer (and haven't really solved my issue).
There is the 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"
}
]
What I failed to do previously I guess is to post what I have so far and explain better what I need. This is what I have right now:
$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;
});
});
};
This filter restricts me to search through only the name
property, while ideally I would like to search through any property (or well, all the properties, rather) and I'd like the filter to work with an array of parameters so that each word would separately look through each property in the object and find a match.
In the previous post a person posted a for loop for it, but that is exactly the kind of unintuitive thing I want to avoid. I know what I want the result to be but I just can't think of an approach (lodash/underscore seemingly almost does something like this, but I think there is something missing from somewhere or I am really bad at understanding the docs).
Examples:
In case I write "google sweden", it will only show the 1 result, if I write "sweden", it would show the one from google and the one from bing. In case I write "in", it should show "bINg" and google "ukraINe" I guess.
This seemed like a much less of a hassle at first but I can't really wrap my head around this using a filter. I really don't have any ideas to post because they have been embarrassingly bad and this is a really grey area for me.
Upvotes: 2
Views: 2498
Reputation: 386570
Version A shapes the result for the whole data set to the wanted set which iterates throu the search words.
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);
}
<div id="out0"></div>
Version B with different approach. Here I collect the objects who match the requirements.
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);
}
<div id="out"></div>
Upvotes: 0
Reputation: 27976
From the question it looks as if you want to filter a list where the values in each item contains every keyword:
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;
})
});
});
Upvotes: 5
Reputation: 3283
Perhaps something like this (note, probably not the most efficient one). Doesn't handle lowercase, but it's simple to add.
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));
Upvotes: 0