Given an array of strings:
x = ["banana","apple","orange"]
is there a built in shortcut for performing wildcard searches?
ie., maybe
x.indexOf("*na*") //returns index of a string containing the substring na
Expanding on Pim's answer, the correct way to do it (without jQuery) would be this:
Array.prototype.find = function(match) {
return this.filter(function(item){
return typeof item == 'string' && item.indexOf(match) > -1;
});
}
But really, unless you're using this functionality in multiple places, you can just use the existing filter method:
var result = x.filter(function(item){
return typeof item == 'string' && item.indexOf("na") > -1;
});
The RegExp version is similar, but I think it will create a little bit more overhead:
Array.prototype.findReg = function(match) {
var reg = new RegExp(match);
return this.filter(function(item){
return typeof item == 'string' && item.match(reg);
});
}
It does provide the flexibility to allow you to specify a valid RegExp string, though.
x.findReg('a'); // returns all three
x.findReg("a$"); // returns only "banana" since it's looking for 'a' at the end of the string.
Extending on #Shmiddty's answer, here are useful JavaScript ideas:
Extend Array with a new method: Array.prototype.method = function(arg) { return result; }
Filter arrays using: Array.filter(function(e) { return true|false; })
Apply formula to elements in an array: Array.map(function(e) { return formula(e); })
Use regular expressions: either /.*na.*/ or new Regex('.*na.*')
Use regular expressions to match: let result = regex.test(input);
Use Array.prototype.reduce to aggergate a result after running a function on every element of an array
i.e. I prefer the input argument to be a regex, so, it gives you either:
A short but universal pattern matching input,
e.g. contains, starts with, ends width, as well as more sophisticated matches
The ability to specify an input pattern as a string
SOLUTION 1: filter, test, map and indexOf
Array.prototype.find = function(regex) {
const arr = this;
const matches = arr.filter( function(e) { return regex.test(e); } );
return matches.map(function(e) { return arr.indexOf(e); } );
};
let x = [ "banana", "apple", "orange" ];
console.log(x.find(/na/)); // Contains 'na'? Outputs: [0]
console.log(x.find(/a/)); // Contains 'a'? Outputs: [0,1,2]
console.log(x.find(/^a/)); // Starts with 'a'? Outputs: [1]
console.log(x.find(/e$/)); // Ends with 'e'? Outputs: [1,2]
console.log(x.find(/pear/)); // Contains 'pear'? Outputs: []
SOLUTION 2: reduce, test
Array.prototype.find = function(regex) {
return this.reduce(function (acc, curr, index, arr) {
if (regex.test(curr)) { acc.push(index); }
return acc;
}, [ ]);
}
let x = [ "banana", "apple", "orange" ];
console.log(x.find(/na/)); // Contains 'na'? Outputs: [0]
console.log(x.find(/a/)); // Contains 'a'? Outputs: [0,1,2]
console.log(x.find(/^a/)); // Starts with 'a'? Outputs: [1]
console.log(x.find(/e$/)); // Ends with 'e'? Outputs: [1,2]
console.log(x.find(/pear/)); // Contains 'pear'? Outputs: []
You can extend the array prototype to find matches in an array
Array.prototype.find = function(match) {
var matches = [];
$.each(this, function(index, str) {
if(str.indexOf(match) !== -1) {
matches.push(index);
}
});
return matches;
}
You can then call find on your array like so
// returns [0,3]
["banana","apple","orange", "testna"].find('na');
using regex can do this in javascript
var searchin = item.toLowerCase();
var str = columnId;
str = str.replace(/[*]/g, ".*").toLowerCase().trim();
return new RegExp("^"+ str + "$").test(searchin);
In addition to everything else that has been said, you can do this:
var x = ["banana", "apple", "orange"];
var y = [];
for (var i in x) {
if (x[i].indexOf('na') > -1) {
y.push(i);
}
}
Results: y = [0]
Related
I am trying to filter some data from an array in a JSON file, based on an input of the form string1, string1,string2, string1,string2,string3 etc., that is, some strings separated by a ,.
What I'm trying to do:
let arrInput = document.getElementById('inputBox').val.split(',');
for(let i = 0; i < arrToFilter.length; i++){
if(.........what to write here?...........){
arrOutput.push(arrToFilter[i]);
}
}
return arrOutput;
If the arrInput had a fixed length, I could accomplish this using indexOf != -1 for each element in arrInput, but here, since the length of arrInput is variable, how can I check if at least one of the strings present in arrInput is also present as a substring in arrToFIlter[i]?
Edit:
Example:
Let arrToFilter be ["abcqwer", "pizza", "definition", "abcdef", "example"]
Case 1 :
Say the input entered (in an <input> element) is abc,def.
For this, the arrOutput should be ["abcqwer", "definition", "abcdef"]
Case 2:
Say the input entered is abc
Expected output : ["abcqwer", "abcdef"]
Simple way is using some and filter,
var string = 'ad,kk,sb';
var array = ['adik', 'klop', 'pp'];
var stringers = string.split(',');
var result = array.filter((arr) => {
var isPresent = stringers.some(stringer => arr.includes(stringer));
return isPresent ? true : false;
});
console.log(result);
You need to iterate both arrays
let arrToFilter = ['abcqwer', 'pizza', 'definition', 'abcdef', 'example'];
let arrOutput = [];
let arrInput = document.getElementById('inputBox').value.split(',');
arrToFilter.forEach(filter => {
arrInput.forEach(input => {
if (!!input && filter.includes(input)) {
arrOutput.push(filter);
}
});
});
// distinct the output
return arrOutput.filter((v, i, a) => i === a.indexOf(v));
I have to write a function that returns all users with a second letter of "h" in their name.
var users = ["Roman","Sherry","Sandrah","Shamaika"];
I started to code something like this but it is not working.
function letter(){
var index = users.indexOf("h") == [1];
return(index);
}
I am new to JavaScript and I am not sure where to start.
You can use filter.
const users = ["Roman","Sherry","Sandrah","Shamaika"];
let filteredUsers = users.filter(user => user.charAt(1) === 'h');
console.log(filteredUsers);
You could filter the array by taking a function which check the character at index 1.
function checkLetter1(string) {
return string[1] === 'h';
}
var users = ["Roman", "Sherry", "Sandrah", "Shamaika"];
console.log(users.filter(checkLetter1));
You are missing filter
var users = ["Roman","Sherry","Sandrah","Shamaika"];
var index = users.filter(a=> a.indexOf("h") === 1);
console.log(index);
You can do something like so:
function usersWithSecondH(users) {
return users.filter(user => user[1] === 'h');
}
So essentially checking the value of the second letter and returning those names in a new array if it matches 'h';
var users = ["Roman","Sherry","Sandrah","Shamaika"];
var t=users.filter((x)=>x.indexOf('h')==1)
console.log(t);
This will do
Currently, your code is looking for the first index of h in the array of user names, which will return incorrect results. Consider using the Array#filter method to select names that match your criteria of the second character being h like so:
var users = ["Roman","Sherry","Sandrah","Shamaika"];
function letter(name){
// Return true if the second character of name is an 'h'
return name[1] === 'h';
}
// Use filter() method to get array of items that satisfy
// the criteria of your letter() function
var filteredUsers = users.filter(letter);
console.log(filteredUsers);
The following function will return the array elements (as a result array) which have the second character as a "h":
var users = ["Roman", "Sherry", "Sandrah", "Shamaika"];
function getMyUsers() {
return users.map(user => user.split(""))
.filter(userChars => userChars[1] == "h")
.map(userChars => user.join(""));
};
console.log(getMyUsers());
The Output:
[ "Sherry", "Shamaika" ]
EDIT: The getMyUsers function can also be coded in a more detailed way as follows:
function getMyUsers2() {
let usersWithH = [];
for (let user of users) {
let userChars = user.split("");
if (userChars[1] == "h") {
usersWithH.push(user);
}
}
return usersWithH;
}
console.log(getMyUsers2()); // prints [ "Sherry", "Shamaika" ]
Let's say I have the following object:
const obj = {
'myApi': ['keyOne', 'keyTwo'],
'myApi.keyOne': ['three', 'four'],
'myApi.keyTwo': [...],
'myApi.keyOne.three': [...]
'myApi.keyOne.four': [...]
}
Now, based on the following string:
const str = "if(myApi.keyOne.three"
I want to match the correct object key, but from right to left. So, in the above example, I want to get obj["myApi.keyOne.three"].
indexOf or str.test methods will not work because they will catch myApi and myApi.keyOne also.
Note that it could be any string, the str is just an example. For example:
while(myApi.keyOne.three) {} // should match obj["myApi.keyOne.three"]
if(myApi.keyOne) {} // should match obj["myApi.keyOne"]
etc.
How can I do this?
To get the key, use a regular expression to match myApi, followed by any number of repeated groups of (a period followed by word characters). Then, you can just access the appropriate key on the object:
const obj = {
'myApi': ['keyOne', 'keyTwo'],
'myApi.keyOne': ['three', 'four'],
'myApi.keyOne.three': ['foobar']
};
function getVal(str) {
const key = str.match(/myApi(?:\.\w+)*/)[0];
console.log(obj[key]);
return obj[key];
}
getVal("if(myApi.keyOne.three");
getVal("while(myApi.keyOne.three) {}");
getVal("if(myApi.keyOne) {}");
Search for the key entry in the pattern:
var result = “”;
Object.keys(obj).forEach(function(key) {
if (str.indexOf(key) !== -1 && key.length > result.length) result = key;
});
console.log(obj[result]);
To make things more dynamic (even if there's no guarantee about myApi):
function findStuff(str, obj) {
const keys = Object.keys(obj);
keys.sort((a, b) => b.length - a.length);
// https://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
const re = new RegExp(keys.map(key => key.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')).join('|'));
const match = str.match(re);
return match && match[0];
}
const obj = {
'myApi': ['keyOne', 'keyTwo'],
'myApi.keyOne': ['three', 'four'],
'myApi.keyTwo': [""],
'myApi.keyOne.three': ["THREE"],
'myApi.keyOne.four': [""]
}
console.log(findStuff('while(myApi.keyOne.three) {}', obj));
We take all the keys from the object, then sort them by descending length (so the longest will be matched first). Then regexp-escape them and stick them together in a regexp alternation.
You can use a regular expression like
myApi(\.\w+)*
Details:
myApi - matches the "myApi" string
(\.\w+)* - matches 0 or more repetitions of those alphanumeric strings which follows a period (.) character
const obj = {
'myApi': ['keyOne', 'keyTwo'],
'myApi.keyOne': ['three', 'four'],
'myApi.keyTwo': ['someVlaue1'],
'myApi.keyOne.three': ['someVlaue2'],
'myApi.keyOne.four': ['someVlaue3']
}
var str1 = 'while(myApi.keyOne.three) {}';
var str2 = 'if(myApi.keyOne) {}';
var regex = /myApi(\.\w+)*/g;
var val1 = obj[ str1.match(regex)[0] ];
var val2 = obj[ str2.match(regex)[0] ];
console.log(val1);
console.log(val2);
How do I return an array of indexes in contents that match the pattern.
var contents = ["Dog is big","Cat is small","Horse is huge"]
(contents,"og") //returns [0,2]
(contents,"at") //returns [1]
(contents,"..") //etc
So, "o" and "g" are both in 0 and 2 but not in 1.
note: the letters don't have to be in that order.
You can use Array.prototype.reduce and Array.prototype.every to filter out the indices which matches your criteria - see demo below:
var contents = ["Dog is big","Cat is small","Horse is huge"];
function filter(filter) {
var f = filter.split('');
return contents.reduce(function(p,c,i){
f.every(e=>~c.indexOf(e)) && p.push(i);
return p;
},[]);
}
console.log(filter("og"));
console.log(filter("at"));
Use Array#forEach and Array#every methods.
var contents = ["Dog is big", "Cat is small", "Horse is huge"]
console.log(get(contents, "og"));
console.log(get(contents, "at"));
console.log(get(contents, ".."));
function get(arr, str) {
// array for storing result
var res = [];
// iterate over string array
arr.forEach(function(v, i) {
// split string into individual character and
// check for each for match
// if all elements matched push the element
if (str.split('').every(function(v1) {
return v.indexOf(v1) > -1;
}))
res.push(i);
});
return res;
}
I want to found if the variable url matches to any value of the array
For example, here's my array:
var arr = ["test", "foo", "bar", "news-[0-999999999999999]*"];
... and my string
var url = "news-294";
I need to check for each arr value if it matches to url, with regex
So I've tried a foreach on the array, new RegExp for each value and then check if it matchs. But It didn't worked well, and It was leaking my browser memory (the CPU was at 24% for a blank page with the script)
How can I do that? Thanks
EDIT: here's my code:
var CMS = {
RegexMatch: function(regex, str, callback) {
while ((m = regex.exec(str)) !== null) {
if(m[0] == str) callback();
}
},
ArrayFindRegex: function(array, str, callback) {
array.forEach(function(e) {
CMS.RegexMatch(new RegExp(e), str, function() {
callback();
});
});
},
Check: function() {
var url = "blabla";
CMS.ArrayFindRegex(["test", "foo", "bar", "news-[0-999999999999999]*"], url, function() {
console.log('wow');
});
}
}
}
Try Array.prototype.filter instead. It's more idomatic than each (or other iteration methods, in this case). filter returns an array with the contents being any matches or empty if none are found.
var arr = ["test", "foo", "bar", "news-[0-999999999999999]*"];
var url = "news-294";
var matches = arr.filter(function(pattern) {
return new RegExp(pattern).test(url);
})
console.log(matches);
The above example logs ["news-[0-999999999999999]*"]. You can assert a positive result based off the length of matches.
If you intend to do regular expression matching, start with regular expressions, not strings.
var arr = [/test/, /foo/, /bar/, /news-\d+/];
Then you can do normal matching without weird string rewrites or intepretations:
var matched = arr.some(re => re.test(...))
if (matched) {
doSomeThing()
}
or
for (re of arr) {
if (re.test(...)) {
doSomeThing();
break;
}
}