Searching a key in javascript object - javascript

I have a building a chrome extension, I have following data as
var data = {}
data["Five, ok"] = "another one"
chrome.storage.sync.set(data)
chrome.storage.sync.get(function(content){console.log(content)})
>> {'Five, ok': "Another one ", 'ok, done': "New one"}
This can grow bigger with many values. (Key is a comma separated value).
I want to get all keys which include (2 different cases, this are user give values)
1. ok
2. done
this values are dynamic, what is the best way to achieve this in JavaScript/ jquery

chrome.storage.sync.get(function(content) {
var keys = Object.keys(content);
var keysOK = keys.filter(function(key){ return key.search(/\b(ok|done)\b/i) });
console.log(keysOK);
});
/\b(ok|done)\b/i finds the keys containing either ok or done
/\bok\b/i finds the keys containing ok
/\bdone\b/i finds the keys containing done
The i at the end makes the search case-insensitive.
As #charlietfl commented it's not efficient. However chrome.sync doesn't allow more than 100kB of data anyway so it's probably not an issue.

Related

What is the best way to itterate over key value pairs nested in an index using javascript?

I am trying to sort sets of associated key value pairs. They look like this:
{"word":"a","votes":9326,"userMade":"FALSE","limiter":"FALSE"},
But organized into labeled subsets of preferably a string or perhaps an index if necessary.
The data-set is a vote-per-use table of most used english words being parsed into pages.
I will be appending them as text to other html elements due to the constraints my use case, makes it a bit tricky, however, for an example I could work with a simple console.log of the page value followed by the console.log of every word value stored within that page. I need the order preserved. so probably indexed. I will also need to be able to sort each page by the votes value, but I think I can figure the rest out for that.
I have found tutorials on how to search through key-value pairs, but I cannot find how to do all of the following with one solution:
A: access the value of word
B: maintain the order of the data-set, allowing me to append them to the matching html element
C: allows me the opportunity to change which set of elements I am appending to when i have finished looping through a single member of the parent index (the one recording the page)
I imagine it is some combination of for/of and for/in, but I'm getting a headache. Please help?
addl info:
function would run at app startup or when the dataset being examined is changed.
function would take a large dataset filled with around 200 page number values, each with 60+ sets of data like the one listed above, the contents of a single page index for example:
{"word":"a","votes":9326,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aaron","votes":4129,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abandoned","votes":1289,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abc","votes":5449,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aberdeen","votes":641,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abilities","votes":2210,"userMade":"FALSE","limiter":"FALSE"},
{"word":"ability","votes":7838,"userMade":"FALSE","limiter":"FALSE"},
{"word":"able","votes":8649,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aboriginal","votes":1837,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abortion","votes":3232,"userMade":"FALSE","limiter":"FALSE"},
{"word":"about","votes":9295,"userMade":"FALSE","limiter":"FALSE"},
{"word":"above","votes":8818,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abraham","votes":867,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abroad","votes":4969,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abs","votes":2415,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absence","votes":4934,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absent","votes":2937,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absolute","votes":5251,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absolutely","votes":5936,"userMade":"FALSE","limiter":"FALSE"},
{"word":"absorption","votes":285,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abstract","votes":7946,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abstracts","votes":1907,"userMade":"FALSE","limiter":"FALSE"},
{"word":"abuse","votes":7238,"userMade":"FALSE","limiter":"FALSE"},
{"word":"academic","votes":7917,"userMade":"FALSE","limiter":"FALSE"},
{"word":"academics","votes":1706,"userMade":"FALSE","limiter":"FALSE"},
{"word":"academy","votes":6755,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acc","votes":6469,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accent","votes":1020,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accept","votes":7547,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acceptable","votes":4907,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acceptance","votes":7273,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accepted","votes":7684,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accepting","votes":1789,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accepts","votes":1535,"userMade":"FALSE","limiter":"FALSE"},
{"word":"access","votes":9031,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessed","votes":2932,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessibility","votes":5702,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessible","votes":5662,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessing","votes":2096,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessories","votes":8875,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accessory","votes":5661,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accident","votes":5664,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accidents","votes":2991,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accommodate","votes":1807,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accommodation","votes":8059,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accommodations","votes":3885,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accompanied","votes":2532,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accompanying","votes":664,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accomplish","votes":1070,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accomplished","votes":2419,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accordance","votes":6434,"userMade":"FALSE","limiter":"FALSE"},
{"word":"according","votes":8282,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accordingly","votes":3003,"userMade":"FALSE","limiter":"FALSE"},
{"word":"account","votes":8996,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accountability","votes":3029,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accounting","votes":7459,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accounts","votes":7507,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accreditation","votes":1605,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accredited","votes":3027,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accuracy","votes":6779,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accurate","votes":6427,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accurately","votes":1493,"userMade":"FALSE","limiter":"FALSE"},
{"word":"accused","votes":2853,"userMade":"FALSE","limiter":"FALSE"},
{"word":"acdbentity","votes":1389,"userMade":"FALSE","limiter":"FALSE"},
and the output would ultimately append the value paired with each word to a specific button through iteration, but also sorted by the page value.
each page is a set of buttons in a 3d object that looks like this:
the text is appended to each button which in turn is a 3d object embeded in an html object using aframe. I can make the appending code.
You can use Object.entries() to get the key value pairs of an object.
var words = [
{"word":"a","votes":9326,"userMade":"FALSE","limiter":"FALSE"},
{"word":"aaron","votes":4129,"userMade":"FALSE","limiter":"FALSE"}
];
words.forEach((wordEntry) => {
var keyValuePairs = Object.entries(wordEntry);
keyValuePairs.forEach((kv) => {
console.log(`key: ${kv[0]} value: ${kv[1]}`);
});
});
my latest attempt looks like this:
for (let p=1; p<129; p++){
for (let b=1; b<68; b++){
let pTpl = (p).toLocaleString(undefined, {minimumIntegerDigits: 3});
let bDbl = (b).toLocaleString(undefined, {minimumIntegerDigits: 2});
var `#fCont${pTpl}${bDbl}` = document.createElement('a-text');
`fCont${pTpl}${bDbl}`.setAttribute('value', 'engWordLib[p,b,0]');
`fCont${pTpl}${bDbl}`.setAttribute('votes', 'engWordLib[p,b,1]');
`fCont${pTpl}${bDbl}`.setAttribute('userMade', 'engWordLib[p,b,2]');
`fCont${pTpl}${bDbl}`.setAttribute('limiter', 'engWordLib[p,b,3]');
`fCont${pTpl}${bDbl}`.setAttribute('visible', 'false');
`fBtn${bDbl}`.appendChild(`#fCont${pTpl}${bDbl}`)
}
}
please note that I havent checked this for errors. I still think this code is to WET and I would prefer the key names for the properties be preserved in the datastructure rather than tacked on when it's appended to the page. I guess I could add a dimension to the array.... seems kind of messy when an object property value has the key value pairs right in it. cant get the iteration of objects in an array down though.... Will continue to persue a cleaner method.

Set the JSON Key to increment inside a loop

I have an array within my json output from a php file which uses the key 0,1,2 etc
I am having trouble accessing the key through javascript. I'm not sure what the issue is with using numbers. All the other data has a text value key which I can access using data.arrayname.key. To get around the issue I would like to set the key to a string with a number at the end so I can reference it back in javascript easily.
The array is pushed to each time in a loop. Within the loop I have tried
$NoOfTips++;
$jsonKey = 'Tip' + $NoOfTips;
$TBarray[$jsonKey]=$line;
array_push($TBarray);
In theory each time the loop goes round NoOfTips should increase by 1 which would also change the key to Tip1,Tip2,etc but obviously something is amiss. Could somebody please explain how why the Key is not being set correctly.
Thanks
To answer the real issue - to access a numeric index in javascript, you can't use dot notation, you would instead use brackets:
var data = { tips: { 1: "one", 2: "two" }, other: [1, { test: "tested" }] }
console.log(data.tips[1], data.other[0], data.other[1].test)
// output: one 1 tested
For the php side, when you do array_push, you have to specify the array you are pushing to, as well as what you are pushing:
array_push($TBarray, $line)
for example. I'm not sure what you are going for there, though.

producing a word from a string in javascript

I have a string which is name=noazet difficulty=easy and I want to produce the two words noazet and easy. How can I do this in JavaScript?
I tried var s = word.split("=");
but it doesn't give me what I want .
In this case, you can do it with that split:
var s = "name=noazet difficulty=easy";
var arr = s.split('=');
var name = arr[0]; //= "name"
var easy = arr[2]; //= "easy"
here, s.split('=') returns an array:
["name","noazet difficulty","easy"]
you can try following code:
word.split(' ').map(function(part){return part.split('=')[1];});
it will return an array of two elements, first of which is name ("noazet") and second is difficulty ("easy"):
["noazet", "easy"]
word.split("=") will give you an array of strings which are created by cutting the input along the "=" character, in your case:
results = [name,noazet,difficulty,easy]
if you want to access noazet and easy, these are indices 1 and 3, ie.
results[1] //which is "noazet"
(EDIT: if you have a space in your input, as it just appeared in your edit, then you need to split by an empty string first - " ")
Based on your data structure, I'd expect the desired data to be always available in the odd numbered indices - but first of all I'd advise using a different data representation. Where is this string word coming from, user input?
Just as an aside, a better idea than making an array out of your input might be to map it into an object. For example:
var s = "name=noazet difficulty=easy";
var obj = s.split(" ").reduce(function(c,n) {
var a = n.split("=");
c[a[0]] = a[1];
return c;
}, {});
This will give you an object that looks like this:
{
name: "noazert",
difficulty: "easy"
}
Which makes getting the right values really easy:
var difficulty = obj.difficulty; // or obj["difficulty"];
And this is more robust since you don't need to hard code array indexes or worry about what happens if you set an input string where the keys are reversed, for example:
var s = "difficulty=easy name=noazet";
Will produce an equivalent object, but would break your code if you hard coded array indexes.
You may be able to get away with splitting it twice: first on spaces, then on equals signs. This would be one way to do that:
function parsePairs(s) {
return s.split(' ').reduce(
function (dict, pair) {
var parts = pair.split('=');
dict[parts[0]] = parts.slice(1).join('=');
return dict;
},
{}
);
}
This gets you an object with keys equal to the first part of each pair (before the =), and values equal to the second part of each pair (after the =). If a string has multiple equal signs, only the first one is used to obtain the key; the rest become part of the value. For your example, it returns {"name":"noazet", "difficulty":"hard"}. From there, getting the values is easy.
The magic happens in the Array.prototype.reduce callback. We've used String.prototype.split to get each name=value pair already, so we split that on equal signs. The first string from the split becomes the key, and then we join the rest of the parts with an = sign. That way, everything after the first = gets included in the value; if we didn't do that, then an = in the value would get cut off, as would everything after it.
Depending on the browsers you need to support, you may have to polyfill Array.prototype.reduce, but polyfills for that are everywhere.

Joining values in an Javascript array

Say I have:
var Certificated = {}
Sub items are added dynamically and variate. Possible outcome:
var Certificated = {
Elementary: ["foo","bar", "ball"]
MiddleSchool: ["bar", "crampapydime"]
};
I want to do the following:
Certificated.Elementary = Certificated.Elementary.join("");
Except I need it to do that on all of the objects inside.
Keep in mind I can't know for sure the titles of nor how many objects will be inside Certificated.
My question is how can I use .join("") on all elements inside Certificated, without calling each one specifically?
EDIT: I am aware .join() is for arrays and the objects inside Certificated are going to be arrays. Therefore the join method.
Does this work?
for (var key in Certificated) {
if (Certificated.hasOwnProperty(key)) {
Certificated[key] = Certificated[key].join("");
}
}
It loops through all properties of Certificated, and makes a quick safe check for the key being a real property, then uses bracket notation - [""] - to do your join.
Quick question - are you sure you want to use join? I know you just provided an example, but you can't call join on a string...it's for arrays. Just wanted to make sure you knew.
Here's a jsFiddle of my code working with arrays being used for the properties:
http://jsfiddle.net/v48dL/
Notice in the browser console, the properties' values are strings because the join combined them with "".

optimize search through large js string array?

if I have a large javascript string array that has over 10,000 elements,
how do I quickly search through it?
Right now I have a javascript string array that stores the description of a job,
and I"m allowing the user to dynamic filter the returned list as they type into an input box.
So say I have an string array like so:
var descArr = {"flipping burgers", "pumping gas", "delivering mail"};
and the user wants to search for: "p"
How would I be able to search a string array that has 10000+ descriptions in it quickly?
Obviously I can't sort the description array since they're descriptions, so binary search is out. And since the user can search by "p" or "pi" or any combination of letters, this partial search means that I can't use associative arrays (i.e. searchDescArray["pumping gas"] )
to speed up the search.
Any ideas anyone?
As regular expression engines in actual browsers are going nuts in terms of speed, how about doing it that way? Instead of an array pass a gigantic string and separate the words with an identifer.
Example:
String "flipping burgers""pumping gas""delivering mail"
Regex: "([^"]*ping[^"]*)"
With the switch /g for global you get all the matches. Make sure the user does not search for your string separator.
You can even add an id into the string with something like:
String "11 flipping burgers""12 pumping gas""13 delivering mail"
Regex: "(\d+) ([^"]*ping[^"]*)"
Example: http://jsfiddle.net/RnabN/4/ (30000 strings, limit results to 100)
There's no way to speed up an initial array lookup without making some changes. You can speed up consequtive lookups by caching results and mapping them to patterns dynamically.
1.) Adjust your data format. This makes initial lookups somewhat speedier. Basically, you precache.
var data = {
a : ['Ant farm', 'Ant massage parlor'],
b : ['Bat farm', 'Bat massage parlor']
// etc
}
2.) Setup cache mechanics.
var searchFor = function(str, list, caseSensitive, reduce){
str = str.replace(/(?:^\s*|\s*$)/g, ''); // trim whitespace
var found = [];
var reg = new RegExp('^\\s?'+str, 'g' + caseSensitive ? '':'i');
var i = list.length;
while(i--){
if(reg.test(list[i])) found.push(list[i]);
reduce && list.splice(i, 1);
}
}
var lookUp = function(str, caseSensitive){
str = str.replace(/(?:^\s*|\s*$)/g, ''); // trim whitespace
if(data[str]) return cache[str];
var firstChar = caseSensitive ? str[0] : str[0].toLowerCase();
var list = data[firstChar];
if(!list) return (data[str] = []);
// we cache on data since it's already a caching object.
return (data[str] = searchFor(str, list, caseSensitive));
}
3.) Use the following script to create a precache object. I suggest you run this once and use JSON.stringify to create a static cache object. (or do this on the backend)
// we need lookUp function from above, this might take a while
var preCache = function(arr){
var chars = "abcdefghijklmnopqrstuvwxyz".split('');
var cache = {};
var i = chars.length;
while(i--){
// reduce is true, so we're destroying the original list here.
cache[chars[i]] = searchFor(chars[i], arr, false, true);
}
return cache;
}
Probably a bit more code then you expected, but optimalisation and performance doesn't come for free.
This may not be an answer for you, as I'm making some assumptions about your setup, but if you have server side code and a database, you'd be far better off making an AJAX call back to get the cut down list of results, and using a database to do the filtering (as they're very good at this sort of thing).
As well as the database benefit, you'd also benefit from not outputting this much data (10000 variables) to a web based front end - if you only return those you require, then you'll save a fair bit of bandwidth.
I can't reproduce the problem, I created a naive implementation, and most browsers do the search across 10000 15 char strings in a single digit number of milliseconds. I can't test in IE6, but I wouldn't believe it to more than 100 times slower than the fastest browsers, which would still be virtually instant.
Try it yourself: http://ebusiness.hopto.org/test/stacktest8.htm (Note that the creation time is not relevant to the issue, that is just there to get some data to work on.)
One thing you could do wrong is trying to render all results, that would be quite a huge job when the user has only entered a single letter, or a common letter combination.
I suggest trying a ready made JS function, for example the autocomplete from jQuery. It's fast and it has many options to configure.
Check out the jQuery autocomplete demo
Using a Set for large datasets (1M+) is around 3500 times faster than Array .includes()
You must use a Set if you want speed.
I just wrote a node script that needs to look up a string in a 1.3M array.
Using Array's .includes for 10K lookups:
39.27 seconds
Using Set .has for 10K lookups:
0.01084 seconds
Use a Set.

Categories

Resources