Using the following
haystack = [{'id':'73','name':'Elvis'},{'id':'45','name':'Beatles'}, etc.]
I want to perform a search whereby I can find Elvis by searching for "elv" or "Elv" (thus, a case insensitive search). Results should return in array thus allowing more than one needle to be returned from my search.
My solution is convert my needle into lowercase, no spaces, and use a for loop to go thru my haystack making checks on a lowercase/nospace name. But I suspect there are other more resource friendly methods (I want to know if there is a better way so I can enhance my skillset/knowledge)
I had thought of using jQuery grep or inArray but both appear to be strict with their comparison. And array.filter() was another idea. But various attempts so far fail.
Thanks
Not sure what you tried but .filter() should have worked. Make sure to lowercase both the search string and the name of the searched items.
var searchTerm = 'Elv'.toLowerCase();
var results = haystack.filter(function(item){
return item.name.toLowerCase().indexOf(searchTerm) > -1;
});
alternatively you could use regexp for the comparison
var searchTerm = 'Elv',
search = new RegExp(searchTerm, 'gi');
var results = haystack.filter(function(item){
return item.name.match(search);
});
You can do it with Array#filter and some String's functions
var haystack = [{ 'id': '73', 'name': 'Elvis' }, { 'id': '45', 'name': 'Beatles' }];
var w = 'elv';
function search(word) {
return haystack.filter(function(e) {
return e.name.toLowerCase().substr(0, word.length) == word;
});
}
console.log(search(w));
Related
I know the heading of this questions seems vague - but it's because I simply don't know how to summarize it appropriately.
I'm working on a project where I enter some text, and it's translated into something else.
There's a fiddle here.
If I enter 4, it translates to the word for.
If I enter b4, it should translate to before.
Instead, it translates to bfor, because it's capturing the variable 4 as a separate variable.
I've tried changing the order, but it doesn't work. Is this a regex problem?
My variables are identified in the JS.
var replaceValues = {
'4' : 'for',
'b4' : 'before'
}
$('.bs-text').keyup(function (event) {
newText = event.target.value;
for (var txt in replaceValues) {
var temp = new RegExp(txt, 'gim');
newText = newText.replace(temp, replaceValues[txt]);
}
$('.human-text').text(newText);
});
As I noted in the comments, JS objects does not have defined order of its keys, so it is not a good idea to count on this when you know the dictionary will get much bigger.
More about this in another SO question: Does JavaScript Guarantee Object Property Order?
Instead, use simple array that will have the order you define. Sorting of this dictionary array can be done in JS too, you do not need to handle this by your own.
var replaceValues = [
{key: '4', value: 'for'},
{key: 'b4', value: 'before'},
];
// sort the values so longer keys go first
replaceValues.sort((a, b) => b.key.length - a.key.length);
$('.bs-text').keyup(function (event) {
var newText = event.target.value;
for (var txt in replaceValues) {
var replacement = replaceValues[txt];
var temp = new RegExp(replacement.key, 'gim');
newText = newText.replace(temp, replacement.value);
}
$('.human-text').text(newText);
});
You could also use ES6 Map, it should have order guarantied. But be aware that it is not enough to create Map from Object:
A Map object iterates its elements in insertion order — a for...of loop returns an array of [key, value] for each iteration.
It should be noted that a Map which is a map of an object, especially a dictionary of dictionaries, will only map to the object's insertion order—which is random and not ordered.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#Objects_and_maps_compared
As mentioned in the comments, you have to look for the longest match first. One option is to generate a single regular expression from the search words, ordered by length, and use a callback to get the correct replacement value.
var replaceValues = {
'4': 'for',
'b4': 'before'
};
// generates something equivalent to `/b4|4/gmi`
var pattern = new RegExp(
Object.keys(replaceValues)
.sort((a, b) => b.length - a.length)
.join('|'),
'gmi'
);
var newText = '4 me b4 me';
console.log(newText.replace(pattern, match => replaceValues[match]));
This works because the regex engine matches alternatives from left to right (i.e. if b4 matches it won't try to match 4). Not sure how this solution scales with more searchwords, but it might actually better because you are only matching the string once instead of n times, i.e. the regex engine doesn't have to traverse the whole string multiple times.
The object property has ":" character within property value
$('.bs-text').keyup(function (event) {
var newText = event.target.value;
if (replaceValues[newText]) {
$('.human-text').text(replaceValues[newText])
};
});
jsfiddle http://jsfiddle.net/je89deam/5/
I have an sorted array e.g
var arr = [ "aasd","march","mazz" ,"xav" ];
And i want to find the first occurance of letter that starts with "m" here it would be 1 . Is thee any way how to do it without looping trought whole array?
You could use a binary search to find any word starting with that letter, then loop backwards until you get the first one.
Is there any way how to do it without looping trought whole array?
Yes, loop until you've found the match.
If you want to avoid a for or while construct, you can use Array's find() method.
For example, arr.find(word => word.startsWith("m")) should return the result you expect (or undefined if there's no such word).
You could use the find() function to search for the first match that meets your constraint.
The startsWith() function could easily handle this :
// Your array
var arr = [ "aasd","march","mazz" ,"xav" ];
// This will find the first match that starts with "m"
arr.find(function(word){ return word.startsWith('m');}); // yields "march"
Or if you needed a bit more extensive pattern matching, you could use a regular expression via the test() function, which can be seen in the following example and handles the same scenario (matching a string that begins with "m") :
// Your array
var arr = [ "aasd","march","mazz" ,"xav" ];
// First match that starts with "m"
var match = arr.find(function(word){ return /^m/i.test(word);}); // yields "march"
Example
var arr = ["aasd", "march", "mazz", "xav"];
var match = arr.find(function(word) { return /^m/i.test(word); });
alert(match);
You dont need to loop through the whole array - only until such time as you find what you're interested in
function findFirstIndex(arr, char){
for(var i=0;i<arr.length;i++){
if(arr[i].substring(0,1) === char)
return i;
}
return -1; // not found
}
You could use Array#some()
The some() method tests whether some element in the array passes the test implemented by the provided function.
function find(letter, array) {
var index;
array.some(function (a, i) {
if (a[0] === letter) {
index = i;
return true;
}
});
return index;
}
var arr = ["aasd", "march", "mazz", "xav"];
document.write(find('m', arr));
I have this code snippet aiming to extract next and last link values from github api...
var types = {},
str = '<https://api.github.com/repositories/1424470/issues?access_token=f554f90b4c95c78091a4202150d4583082dab1ce&page=2>; rel="next", <https://api.github.com/repositories/1424470/issues?access_token=f554f90b4c95c78091a4202150d4583082dab1ce&page=7>; rel="last"',
rex = /\s*<https?:\/\/api.github.com\/.+?&page=(\d+)>;\s*rel="(\w+?)"(?:,|$)/g;
// use regex replace method to capture multiple groups multiple times
str.replace(rex, function(_, page, type){
types[type] = +page;
});
console.log(types);
// {next: 2, last: 7}
It is functioning correctly, but feels like a mis-use of regex replace method, where I am not returning anything, but using it only for the sake of having a callback for each match, which I use to build up an output object.
I would prefer some kind of matchAll, returning multi-dimensional array of matches, and parts.
Is there a better way to handle this case in javascript?
You can use the exec() method in a loop, pushing the match results to a multi-dimensional array.
function find_all(re, s) {
var types = [];
while (m = re.exec(s)) {
types.push([m[2], m[1]])
}
return types;
}
var regex = new RegExp('<https?://[^>]+page=(\\d+)>;\\s*rel="([^"]+)"', 'gi');
find_all(regex, str) //=> [ [ 'next', '2' ], [ 'last', '7' ] ]
I have a webpage where if something typed in search box it then iterates through a file for that value. I need it so that search/find not case sensitive. The case sensitivity must remain in the file but for comparison purposes it disregards the case.
So currently I am using underscore command:
arr=_.where(arr,filter);
but the 2 arrays arr and filter - I need them to be compared/used regardless of case so the end result arr contains results which will mixture of upper and lower case but matches value(s) in arr.
Try using filter instead:
var filter = ["Apple", "bANAna", "orange"];
var arr = ["apPle", "ORANGE"];
// make filter lower case once
var filterLower = _.invoke(filter, "toLowerCase");
var arr2 = _.filter(arr, function(v) {
// make entry lower case and see if it is in filterLower
return _.contains(filterLower, v.toLowerCase());
});
console.dir(arr2);
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
Unfortunately, JS is not great when it comes to internationalized case-insensitive string comparison. If you're just sticking to ASCII though, the solution is fairly straightforward (using filter though, not where):
function getMatches(query, arr) {
var lowerQuery = query.toLowerCase();
return _.filter(arr, function(term) {
return term.toLowerCase() == lowerQuery;
});
}
Or if you want to precompute everything because you expect to make a lot of queries in the same JS session:
var index = _.groupBy(arr, function(term) { return term.toLowerCase(); });
// Post-process index to reduce memory footprint by turning redundant values to nulls
// (which take up less memory than arrays with a string in them).
index = _.object(_.map(index, function(terms, key) {
return [key, (terms.length == 1 && terms[0].toLowerCase() == terms[0] ? null : terms)];
}));
function getMatches(query) {
var lowerQuery = query.toLowerCase();
return (lowerQuery in index ? index[lowerQuery] || lowerQuery : []);
}
This second method has the advantage of only computing toLowercase() the minimal number of times and minimal data storage because of the post-processing step.
Here's a JSFiddle for both
I'm beginning to learn Javascript, and I want to create a function that can sort through an array and compare two values (probably string values).
For example, if there are 50 different words, but there are two "banana" words, I want to know that. Any help on this would be appreciated. Thanks!
You can use filter to find all items that satisfies a filter function. I believe that by sort, you meant traverse or iterate.
E.g.
var words = ['test', 'banana', 'banana', 'other'];
var bananaCount = words.filter(function (word) {
return word == 'banana';
}).length;
console.log(bananaCount); //2
The function needs to work without explicitly stating the word
'banana'. The function needs to find 'banana' programmatically - Team6Labs
Well, you can just adapt the above exemple:
countOfWord(words, 'banana'); //2
function countOfWord(words, word) {
return words.filter(function (w) {
return w == word;
}).length;
}