I have an array of Strings in JavaScript. I am trying to develop a function that
Takes a substring as an input.
Searches through the array.
Returns strings from the array close to the substring. The list will be provided as suggestions to the caller.
For example:-
Array contains the below entries.
Hello
What is hello
World
Spacearenotthereinthishello
HELLO
Highway to hell
JavaScript
StackOverflow
I invoke the function as shown below
var result[] = searchFunc('hell');
The result array should contain
Hello
What is hello
Spacearenotthereinthishello
HELLO
Highway to hell
It is possible that the array could contain atleast 100 strings ( or more). I am looking for a scalable solution.
Initially, i figured i should sort and then do a binary search but its cumbersome to do if you wanna pull of all the suggestions from the master array for a particular string input. I am looking for algorithms that can help me achieve a faster search. I am not that worried about insertion timecomplexity in master array.
I did look up multiple stack overflow posts. They do speak about searching a big book for specific strings. None of them talk about returning suggestions from an array for a substring.
Your help is appreciated.
YourArray.filter() will do the job. Quick prototype:
var results = arrayName.filter(function(value) {
return value.toLowerCase().indexOf(searchStr.toLowerCase()) >= 0;
});
Quick Answer (TL;DR)
Use Array.prototype.filter()
Detailed Answer
Context
Javascript
Array filtering
Problem
Scenario: Developer wishes to filter an array for matches on a substring
Solution
// declare array of string fragments
myArrayOfStringFragments = /* TODO: get the content [ ... ] */
// optional step, normalize all strings to lower-case
/* TODO: input normalization with Array.prototype.map() or something similar */
// declare comparison function
function strContainsMatch(slookfor) {
return slookfor.includes("ello");
}
// iterate using Array.prototype.filter()
var filtered = myArrayOfStringFragments.filter(strContainsMatch);
Pitfalls
Data input normalization (are differences based on letter-case significant?)
string comparison based on non-ascii characters
string.includes() method may not be available, instead use string.indexOf()
avoiding false-postive matches based on chosen substring
(e.g., if you are looking for hello then hell will match more than you want, and it will miss Hello if your input is not normalized to lowercase)
See also
How can I only keep items of an array that match a certain condition?
Alternate solution would be to create a regex to do the same.
var condition = new RegExp("hell", 'g');
var results = arrayName.filter(function(value) {
return condition.test(value.toLowerCase())
});
Related
I use Zapier to automate many of our business functions, which is great, but I got stuck trying to count the number of arrays or, if you like, a particular word pattern that comes from a string. I can tidy up the string with Zapier formatter, but cannot figure out how to carry out a count.
Here is an example of a tidied string where " have been removed:
[{Name:Jon,Surname:Smith},{Name:David,Surname:Michael},{Name:Sam,Surname:Fields},{Name:Katy,Surname:Milnes}]
In this instance I would want the count on say "Name" to return 4.
I have looked at different code examples for counting words but cannot execute them correctly in the code action of Zapier. This is probably really straight forward but I do not come from a coding background so a simple Java (or Python) script to drop into the Zapier code action or some pointers on how to solve this would be greatly appreciated.
Thanks
What are you really trying to achieve by trying to count the word?
Do you just want to know the number of objects the array contains? If that is the case something like this would work. Assuming that the array is in your inputData for the code step.
var data = JSON.stringify([{'Name':'Jon', 'Surname':'Smith'},{'Name':'David','Surname':'Michael'},{'Name':'Sam','Surname':'Fields'},{'Name':'Katy','Surname':'Milnes'}]);
var inputData = {objArr: data};
// Do not insert the above lines in your code step.
// Set the objArr to your array in the inputData step.
var parsedObjArr = JSON.parse(inputData.objArr);
// Skip the above step if the array is not in the inputData object.
var arrLen = parsedObjArr.length
console.log('Array Length: ', arrLen);
// The line below outputs data from the code step.
output = {arrLen}
Also note, you do not need to remove the quotes from the JSON string.
If the array is not in the inputData of the code step, you can just directly use the length method on the array.
Well in Python you can convert the json string into dictionary with key as the name. Length of dictionary is what you are looking for. Here is the example:
import json
from collections import defaultdict
d=defaultdict(list)
x=json.dumps([{'Name':'Jon', 'Surname':'Smith'},{'Name':'David','Surname':'Michael'},{'Name':'Sam','Surname':'Fields'},{'Name':'Katy','Surname':'Milnes'}])
json_string=json.loads(x)
for obj in json_string:
if(obj['Name'] in d):
d[obj['Name']].append([obj['Name']+' '+obj['Surname']])
else:
d[obj['Name']]=[obj['Name']+' '+obj['Surname']]
print(len(d))
I'm trying to write a spell-check script. Let's say I have a keyed list of 10 English words:
var wordList = {
"moas" : "moas",
"moat" : "moat",
"moated" : "moated",
"moating" : "moating",
"moatlike" : "moatlike",
"moats" : "moats",
"mob" : "mob",
"mobbed" : "mobbed",
"mobber" : "mobber",
"mobbers" : "mobbers",
}
and one misspelled word: "motelike" which I want to correct from the word list by finding the most similar word. If the closest word has a similarity above a certain threshold, I'll replace it.
I could put something together that loops through all of the words and checks each letter for a match, but that would be monstrously expensive to process when my dictionary is > 200,000 items). I think there must be a way to target the word's possible matches more efficiently than looping the whole array with the advantage of having a keyed list.
I can't think of how to go about doing this. It seems like it shouldn't be that hard, but I'm drawing a blank on how to get it done. Maybe something with regex involved?
The keyword you're looking for is fuzzy string searching. There are many libraries for that, for example fuzzyset.js. You use it like this:
f = FuzzySet(['moas', 'moat', 'moated', 'moating', 'moatlike', 'moats', 'mob', 'mobbed', 'mobber', 'mobbers']);
f.get('moateb');
// returns [[0.8333333333333334, 'moated']]
// (array of pairs [score, match])
Of course, you can implement it yourself instead of using a library. This wikipedia article is about this problem.
I am reading data from a text file and I am interested in a specific pattern that I have isolated with the following:
cleanString = queryString.match(/^NL.*/gm);
This results in the array:
["NL:What are the capitals of the states that border the most populated states?",
"NL:What are the capitals of states bordering New York?",
"NL:Show the state capitals and populations.",
"NL:Show the average of state populations.",
"NL:Show all platforms of Salute generated from NAIs with no go mobility."]
I then want to get rid of all patterns matching NL: so I am left with just a natural language question or statement. To accomplish this, I convert the array to a string , and then use .split() to create the desired array like so:
var nlString = cleanString.toString();
var finalArray = nlString.split(/NL:/gm);
There are two problems I am having.
1. I end up with an extra value of an empty string at index [0] in the resulting array, and
2. I now have a comma literal appended to the strings in the array:
["", "What are the capitals of the states that border the most populated states?,",
"What are the capitals of states bordering New York?,",
"Show the state capitals and populations.,",
"Show the average of state populations.,",
"Show all platforms of Salute generated from NAIs with no go mobility."]
How can I eliminate these problems? Also If someone has a more elegant approach to reading a big ugly text file delimited by line breaks and isolating strings of interest I am all eyes.
Thanks in advance for any suggestions.
You don't have to convert the array to a string, then remove the NL: strings and convert back to an array, just iterate over the array and remove that string in each index
var arr = arr.map(function(el) {return el.replace('NL:','');});
FIDDLE
a regular for loop would also work if older browsers is an issue
var finalString = nlString.replace(/NL:/gm, '');
Warning : map is not supported by IE8 and below. Here is an alternative :
var array = string.split(/\n*NL:/);
array.shift(); // that's it
Demo here : http://jsfiddle.net/wared/BYgLd/.
I have a multi-dimensional array like this:
1 2 3
4 5 6
Now I need to convert this array into a string like 1,2,3;4,5,6.
Can any one suggest how to do this, please?
simply use the join method on the array.
> [[1,2,3],[4,5,6]].join(';')
'1,2,3;4,5,6'
It's lucky that you simply don't have to consider how the apply the join method on the inner lists, because a list is joined by comma by default. when a list is coerced into a string, it by default uses commas to separate the items.
As it was already mentioned by qiao, join() is not recursive.
But if you handle the recursion yourself you should acquire the desired result, although in a rather inelegant way.
var array = [[1,2,3],[5,6,7]];
var result = [];
array.forEach(
function(el){
result.push(
el.join(",")
);
});
result.join(";");
If you need to serialize an array into a string and then deserialize it later to get an array from the string you might want to take a look at JSON:
http://www.openjs.com/scripts/data/json_encode.php
Try this:
array.toString();
See here for reference: http://www.w3schools.com/jsref/jsref_tostring_array.asp
See answer by qiao for a much nicer approach to multidimensional arrays like this.
I have list of students displaying in a page and I am storing the student information as object with id and name.
I want to add search box to search students if I got a scroll bar in the list.
And update the students list according to the search string.
Right now i am iterating student object array and checking the index of the search string in the name.
Is there any better algorithm to increase the performance.
// my code:
search = function(data,queryString)
{
var res = new array();
for(stu in data){
if(stu.name.search(queryString) != -1){
res.push(stu);
}
}
return res;
}
You can build a sorted index and use binary search. Multiple indices if you need to search by multiple criteria, e.g. name or ID. Simpler to implement than a tree.
You want to look for a trie-datastructure or a radix-trie or a crit-bit trie where empty nodes are compressed. You want to look for a kart-trie a special version of the radix-trie where there is only 2 edges in a node. In general a trie is good for text search algorithm, for example a dictionary. I have done an implementation of the kart-trie in php at phpclasses.org ( kart-trie ). You are welcome to download and play with it.