I am trying to generate a unique random string.
var string = Math.floor( Math.random() * 1000 ) + Date.now();
The above method which I am using right now gives me too long a string and I want a shorter unique one.
Here is a workaround to avoid the issue of repeated ids:
var GenRandom = {
Stored: [],
Job: function(){
var newId = Date.now().toString().substr(6); // or use any method that you want to achieve this string
if( this.Check(newId) ){
this.Job();
}
this.Stored.push(newId);
return newId; // or store it in sql database or whatever you want
},
Check: function(id){
for( var i = 0; i < this.Stored.length; i++ ){
if( this.Stored[i] == id ) return true;
}
return false;
}
};
jsFiddle
Based on Tushar's suggestion, (new Date().getTime()+'').substr(6,7) will give you a 7-digits unique number. Not random, but unique... at least for a certain time. Since it's based on timestamp, it is actually milliseconds time. Since the length is 7 digits, it will loop from 0000000 to 9999999 every 1000 seconds, that's roughly 17 minutes. But you can't expect a higher "level of uniqueness" with only 7 digits. It may be enough for your application, depending on what you want to achieve with that.
Edit
Following up with your comment : you want a unique SECOND number, so millisecond is no use to you (should have mentioned the seconds in your question).
You could give an invoice the number of the current second, which is (new Date().getTime()+'').substr(3,7). That would be perfect, if the unique number was not limited to 7 digits. This makes 9.999.999 possible seconds, which is... around 115 days.
With 9 digits, you could print unique invoices numbers every second for 316 years.
So in my opinion, your only solution is just to start counting invoices from 0000001, then 0000002, etc, and keeping track of that somewhere to ensure uniqueness. I don't get how generating a random number between 0 and 9.999.999 will make invoices numbering more efficient or easier to track.
For an invoice number you should guarantee a unique identifier no matter how long. In which case I'll suggest using an UUID/GUID. See http://guid.us/GUID/PHP for two implementations (windows-COM/non-windows). If you are not familiar with the concept of UUID, check wikipedia here: http://en.wikipedia.org/wiki/Universally_unique_identifier .
Another option for you is to use mysql's native uuid generator:
select uuid();
This you can also use in your insert queries, like:
insert into mytable (id, data) values (uuid(), 'mytext');
Of course your table structure needs to be adjusted. Personally I find it best to use traditional integer auto_inc id as primary key, along with a guid field to use in replication/export/etc as key.
EDIT:
There apparently is also a uuid_short() function in mysql (since 5.1.20).
SELECT UUID_SHORT();
92395783831158784
See https://dev.mysql.com/doc/refman/5.1/en/miscellaneous-functions.html#function_uuid-short
Related
How can I create a random 16 digit number that doesn't previously exist in a list?
Let's say I have the following list:
const nums = [7856328870763265, 0107654389657487];
I need a function to generate random 16 digit numbers but that doesn't create duplicates.
I have the following:
const val = Math.floor(1000 + Math.random() * 9000).toString();
const random16digitnumber = +val+val+val+val;
console.log(random16digitnumber);
console.log(typeof random16digitnumber);
But im afraid at some point it will start creating duplicates. I'm using the random16digitnumber as a primary key in a SQL database for a small school project.
So going back to my example, how can I create a random 16 digit number that doesn't previously exist in an array?
I don't know much about JavaScript but I'm going to give you a general solution.
You need to use a loop statement to loop through the list to check whether the generated number is in the array. If it is not in the array then append/push it to the list. Else regenerate the random number.
Could have written it in php or python
I'll answer with an inline comment. I left your algo "as is". There might be reasons of why you're doing it this way; so I just implemented the logic you've wished for.
const nums = [7856328870763265, 0107654389657487];
const getNextRandomNumber = () => {
const val = Math.floor(1000 + Math.random() * 9000).toString();
const candidate = +val+val+val+val;
// the generated number is part of the list;
// recursively call this function to generate another one
// (this works like a loop, just using call recursion)
// until a number is found that is not part of the list
// then the return below this if() is triggered
// and the "good" candidate is returned
if (nums[candidate]) {
return getNextRandomNumber();
}
// parseInt makes sure the string is converted back to number
// making sure we're using base 10, even if the first digit
// might be 0
return parseInt(candidate, 10);
}
// push() adds an element to the array
// the return value (100% guaranteed to be collision free random number)
// is added via the function call. The function logic makes sure
// it is absolutely unique
nums.push(getNextRandomNumber());
If you want true randomness without duplicates, then you will need to every time check the list to ensure that it's not been included. Eventually that could become a drag on the system, but there's no alternative.
If you want a small enough chance of duplicates appearing that your code can likely ignore it (unless you have phenomenal volume), then GUIDs are probably your best bet... but these are far longer than 16 digits.
However, if you want numbers that appear at a casual glance to be random, although they are far from it, then a simple algorithm will give you all 10^16 numbers in a random-looking order. We can achieve this by taking subsequent numbers as a linear transform of the current ones. We can multiply our current value by some number, a and add another value, b, then take the last 16 digits to get the next value. So long as a and b have no common proper factors and neither has any common proper factors with 10^16, this process will cycle through all numbers from zero to 9999999999999999 in a seemingly random order.
The easiest way to ensure there are no common factors is just to choose two 16-digit primes, which we can do at a site like https://bigprimes.org/.
If we can keep hold of or easily look up the last-used id, then we can write it like this:
const a = BigInt ( '7791448648907857')
const b = BigInt ( '2320712743817497')
const c = BigInt ('10000000000000000')
const nextId = (previousId) =>
((a * BigInt(previousId) + b) % c)
.toString () .padStart ('0', 16)
const lastRecord = {id: '1234567890123456', more: 'fields'}
console .log (nextId (lastRecord .id))
If we can't easily keep track of the last id, but can keep a sequential counter, say n, we can always generate it using the formula
id_n = (a ** n + b * ((a ** n - 1) / (a - 1))) % c
That would involve efficiently managing modular exponentiation, but that's a well-solved problem and is easy enough to implement.
Don't forget that this is no only not cryptographically secure, it's far far from random. But it will give you random-looking number without repetitions.
I want to test if a local_key already exists, if it exists generate another local_key and check again
// Here I go throught an object and try to return a index
const local_key = messagesRow.map((message, key) => {
return message.local_key;
}).indexOf(message.local_key);
// If it returns 0 or bigger, it means that the local_key already exists
if(local_key >= 0){
message.local_key = Math.floor(Math.random() * 9999);
}
EDIT
I want to recheck every time, cause if the local_key exists and I generate another one, this new local_key maybe exists too
This will work, but you are iterating over the whole array, where you only need one match. I would recommend to use some javascript library like underscore (http://underscorejs.org/) which provides nice find function.
Using random number from 0 to 99999 is not a good solution - there is probability that you will generate duplicate number. Better choice would be some UUID / GUID
(see duscussion here: Create GUID / UUID in JavaScript? ) - and there will be no need at all to search for it in array as this is unique
The best way to generate a key is using uniqid
$id = md5(uniqid(date('d/m/Y H:i'), true));
So I am using mongoose and node.js to access a mongodb database. I want to bump up each result based on a number (they are ordered by date created if none are bumped up). For example:
{ name: 'A',
bump: 0 },
{ name: 'B',
bump: 0 },
{ name: 'C',
bump: 2 },
{ name: 'D',
bump: 1 }
would be retreived in the order: C, A, D, B. How can this be accomplished (without iterating through every entry in the database)?
Try something like this. Store a counter tracking the total # of threads, let's call it thread_count, initially set to 0, so have a document somewhere that looks like {thread_count:0}.
Every time a new thread is created, first call findAndModify() using {$inc : {thread_count:1}} as the modifier - i.e., increment the counter by 1 and return its new value.
Then when you insert the new thread, use the new value for the counter as the value for a field in its document, let's call it post_order.
So each document you insert has a value 1 greater each time. For example, the first 3 documents you insert would look like this:
{name:'foo', post_order:1, created_at:... } // value of thread_count is at 1
{name:'bar', post_order:2, created_at:... } // value of thread_count is at 2
{name:'baz', post_order:3, created_at:... } // value of thread_count is at 3
etc.
So effectively, you can query and order by post_order as ASCENDING, and it will return them in the order of oldest to newest (or DESCENDING for newest to oldest).
Then to "bump" a thread in its sorting order when it gets upvoted, you can call update() on the document with {$inc:{post_order:1}}. This will advance it by 1 in the order of result sorting. If two threads have the same value for post_order, created_at will differentiate which one comes first. So you will sort by post_order, created_at.
You will want to have an index on post_order and created_at.
Let's guess your code is the variable response (which is an array), then I would do:
response.sort(function(obj1, obj2){
return obj2.bump - obj1.bump;
});
or if you want to also take in mind name order:
response.sort(function(obj1, obj2){
var diff = obj2.bump - obj1.bump;
var nameDiff = (obj2.name > obj1.name)?-1:((obj2.name < obj1.name)?1:0);
return (diff == 0) ? nameDiff : diff;
});
Not a pleasant answer, but the solution you request is unrealistic. Here's my suggestion:
Add an OrderPosition property to your object instead of Bump.
Think of "bumping" as an event. It is best represented as an event-handler function. When an item gets "bumped" by whatever trigger in your business logic, the collection of items needs to be adjusted.
var currentOrder = this.OrderPosition
this.OrderPosition = currentOrder - bump; // moves your object up the list
// write a foreach loop here, iterating every item AFTER the items unadjusted
// order, +1 to move them all down the list one notch.
This does require iterating through many items, and I know you are trying to prevent that, but I do not think there is any other way to safely ensure the integrity of your item ordering - especially when relative to other pulled collections that occur later down the road.
I don't think a purely query-based solution is possible with your document schema (I assume you have createdDate and bump fields). Instead, I suggest a single field called sortorder to keep track of your desired retrieval order:
sortorder is initially the creation timestamp. If there are no "bumps", sorting by this field gives the correct order.
If there is a "bump," the sortorder is invalidated. So simply correct the sortorder values: each time a "bump" occurs swap the sortorder fields of the bumped document and the document directly ahead of it. This literally "bumps" the document up in the sort order.
When querying, sort by sortorder.
You can remove fields bump and createdDate if they are not used elsewhere.
As an aside, most social sites don't directly manipulate a post's display position based on its number of votes (or "bumps"). Instead, the number of votes is used to calculate a score. Then the posts are sorted and displayed by this score. In your case, you should combine createdDate and bumps into a single score that can be sorted in a query.
This site (StackOverflow.com) had a related meta discussion about how to determine "hot" questions. I think there was even a competition to come up with a new formula. The meta question also shared the formulas used by two other popular social news sites: Y Combinator Hacker News and Reddit.
I'm building an autosuggest for names. When the user types in the textbox, it hits the server and runs this:
var names = [ list of 1000 names ]; //I have a list of 1000 names, this is static.
var query = 'alex';
var matched_names = [];
//This is when it gets slow....
names.forEach(function(name){
if(name.indexOf(query) >= 0){
matched_names.push(name);
}
});
return matched_names;
How can I make this faster? I'm using Node.js
If the names are static then move this code to the client and run it there. The only reason to run code like this on the server is if the data source is dynamic in some way.
Doing this logic client-side will dramatically improve performance.
You should probably use filter instead, for one thing, because it's native:
var names = [ /* list of 1000 names */ ];
var query = 'alex';
var matched_names = names.filter(function(name) {
return name.indexOf(query) > -1;
});
return matched_names;
If you store the names in sorted order, then you can use binary search to find the region of names within the sorted order that start with the fragment of name that the user has typed so far, instead of checking all the names one by one.
On a system with a rather odd programming language, where I wanted to find all matches containing what the user had typed so far in any position, I got a satisfactory result for not much implementation effort by reviving http://en.wikipedia.org/wiki/Key_Word_in_Context. (Once at university I searched through a physical KWIC index, printed out from an IBM lineprinter, and then bound as a document for just this purpose.
I would suggest you to do this stuff on the client-side and prefer (for now) a while loop instead of a filter/forEach approach:
var names = [ /* list of 1000 names */ ]
, query = 'alex'
, i = names.length
, matched_names = [];
while(i--){
if(names[i].indexOf(query) > -1){
matched_names.push(names[i]);
}
}
return matched_names;
This will be much faster (even if filter/forEach are natively supported). See this benchmark: http://jsperf.com/function-loops/4
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.