Java: Unique 10 digit ID - java

I need to generate a unique 10 digit ID in Java. These are the restrictions for this ID:
Only Numeric
Maximum 10 digits
Possible to create up to 10 different IDs per second
Has to be unique (even if the application re-starts)
Not possible to save a number in the Database
As fast as possible NOT to add much lattency to the system
The best solution I found so far is the following:
private static int inc = 0;
private static long getId(){
long id = Long.parseLong(String.valueOf(System.currentTimeMillis())
.substring(1,10)
.concat(String.valueOf(inc)));
inc = (inc+1)%10;
return id;
}
This solution has the following problems:
If for any reason there is a need to create more than 10 IDs per seccond, this solution won't work.
In about 32 years this ID could be repeated (This is probably acceptable)
Any other solution to create this ID?
Any other problem I haven't thought of with mine?
Thanks for your help,

This is a small enhancement to yours but should be resilient.
Essentially, we use the current time in milliseconds unless it hasn't ticked since the last id, in which case we just return last + 1.
private static final long LIMIT = 10000000000L;
private static long last = 0;
public static long getID() {
// 10 digits.
long id = System.currentTimeMillis() % LIMIT;
if ( id <= last ) {
id = (last + 1) % LIMIT;
}
return last = id;
}
As it is it should manage up to 1000 per second with a comparatively short cycle rate. To extend the cycle rate (but shorten the resolution) you could use (System.currentTimeMillis() / 10) % 10000000000L or (System.currentTimeMillis() / 100) % 10000000000L.

This may be a crazy idea but its an idea :).
First generate UUID and get a string representation of it with
java.util.UUID.randomUUID().toString()
Second convert generated string to byte array (byte[])
Then convert it to long buffer: java.nio.ByteBuffer.wrap( byte
digest[] ).asLongBuffer().get()
Truncate to 10 digits
Not sure about uniqueness of that approach tho, I know that you can rely on uniqueness of UUIDs but haven't checked how unique are they converted and truncated to 10 digits long number.
Example was taken from JavaRanch, maybe there is more.
Edit: As you are limited to 10 digits maybe simple random generator would be enough for you, have a look into that quesion/answers on SO: Java: random long number in 0 <= x < n range

private static AtomicReference<Long> currentTime = new AtomicReference<>(System.currentTimeMillis());
public static Long nextId() {
return currentTime.accumulateAndGet(System.currentTimeMillis(), (prev, next) -> next > prev ? next : prev + 1) % 10000000000L;
}

What means that it has to be unique? Even across more currently running instances? It break your implementation.
If it must be unique across universe, the best solution is to use UUID as it's mathematically proven identifier generator as it generates unique value per universe. Less accurate number brings you collisions.
When there is only one concurrent instance, you can take current time in millis and solve 10ms problem using incrementation. If you sacrifice proper number of last positions in the number you can get many number within one milliseconds. I would than define the precision - I mean how much unique numbers do you need per seconds. You will solve the issue without any persistence using this approach.

Related

I'm working on Euler 12 , the code i have seems to workes properly but too slow , very very slow. How can i modify it to run faster?

Like i sad , i am working on Euler problem 12 https://projecteuler.net/problem=12 , i believe that this program will give the correct answer but is too slow , i tried to wait it out but even after 9min it still cant finish it. How can i modify it to run faster ?
package highlydivisibletriangularnumber_ep12;
public class HighlyDivisibleTriangularNumber_EP12 {
public static void findTriangular(int triangularNum){
triangularValue = triangularNum * (triangularNum + 1)/2;
}
static long triangularValue = 0l;
public static void main(String[] args) {
long n = 1l;
int counter = 0;
int i = 1;
while(true){
findTriangular(i);
while(n<=triangularValue){
if(triangularValue%n==0){
counter++;
}
n++;
}
if(counter>500){
break;
}else{
counter = 0;
}
n=1;
i++;
}
System.out.println(triangularValue);
}
}
Just two simple tricks:
When x%n == 0, then also x%m == 0 with m = x/n. This way you need to consider only n <= Math.ceil(sqrt(x)), which is a huge speed up. With each divisor smaller than the square root, you get another one for free. Beware of the case of equality. The speed gain is huge.
As your x is a product of two numbers i and i+1, you can generate all its divisors as product of the divisors of i and i+1. What makes it more complicated is the fact that in general, the same product can be created using different factors. Can it happen here? Do you need to generate products or can you just count them? Again, the speed gain is huge.
You could use prime factorization, but I'm sure, these tricks alone are sufficient.
It appears to me that your algorithm is a bit too brute-force, and due to this, will consume an enormous amount of cpu time regardless of how you might rearrange it.
What is needed is an algorithm that implements a formula that calculates at least part of the solution, instead of brute-forcing the whole thing.
If you get stuck, you can use your favorite search engine to find a number of solutions, with varying degrees of efficiency.

System.currentTimeMillis() to int returns negative value

I am developing an app in which I am adding views dynamically and assigning an unique id using but it is returning negative value:
long time = System.currentTimeMillis();
view.setId((int)time);
So I searched on google and found another solution but however it also doesn't work. It also returns negative value:
Long time = System.currentTimeMillis();
view.setId(time.intValue());
So how can I convert long value returned by System.currentTimeMills() to int safely?
System.currentTimeMills() returns 1505645107314 while converting to int returns -1888413582.
The value will be changed when a large long value is casted to int. You may want to divided the time by 1000 to get time in seconds, or subtract the value from time of 1 day ago (depending upon the uniqueness you prefer) and use it as the id of the view.
view.setId((int)(time/1000)); //this gives unique id for every second.
Edit
Use following code to get unique id for every millisecond:
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DATE, -1);
long yesterday = calendar.getTimeInMillis();
int uniqueId = (int) (yesterday - System.currentTimeMillis());
currentTimeMillis returns a long, which can sometimes not fit into an int. Therefore, I don't think you should use this as a way to set unique int ids for views.
If you want a unique int for each of the views you create, try this approach, create a static counter thingy:
static int nextViewID = 0;
When you create a new view, you just
view.setId(nextViewID);
nextViewID++;
If you want a random unique integer, you can do something like this:
Create a static Set
Generate a random integer using java.util.Random
Try to add the number to the set
Keep generating another integer until you successfully added the number to the set
This is normal. Casting from a large data type (such as long) to a smaller data type (like int), in some cases, might lead to a change in value. You can devise other means by dividing by a certain preset constant (say 10,000). For example:
Long t = System.currentTimeMillis() / 10000;
view.setId((int) t);
This would surely give you a positive value!
You can't do it. Why do you use time as unique id? Bad approach.
For instance, 2147483648 would be represented as -2147483648. For small values, casting is enough:
long l = 42;
int i = (int) l;
However, a long can hold more information than an int, so it's not possible to perfectly convert from long to int, in the general case.
You can use Hash values within integer limit as unique id.

How can I maintain probability across multiple executions in Java

Firstly I am not the greatest with Math, so please excuse any ignorance relating to that. I am trying to maintain probability based randomness across multiple executions but I am failing. I have this input in a JSONObject
{
"option1": 25,
"option2":25,
"option3" :10,
"option4" :40
}
This is my function that selects a value from the above JSONObject based on the probability assigned:
public static String selectRandomoptions(JSONObject options) {
String selectedOption = null;
if (options != null) {
int maxChance = 0;
for (String option : options.keySet()) {
maxChance += options.getInt(option);
}
if (maxChance < 100) {
maxChance = 100;
}
Random r = new Random();
Integer randomValue = r.nextInt(maxChance);
int chance = 0;
for (String option : options.keySet()) {
chance += options.getInt(option);
if (chance >= randomValue) {
selectedOption = options.toLowerCase();
break;
}
}
}
}
the function behaves within a reasonable error margin if I call it x amount of times in a single execution ( tested 100+ calls), the problem is that I am running this every hour to generates some sample data in an event-driven app to verify our analytics process/data but we need it to be somewhat predictable, at least within a reasonable margin?
Has anyone any idea how I might approach this? I would rather not have to persist anything but I am not opposed to it if it makes sense or reduces complexity/time.
The values returned by Random.nextInt() are uniformly distributed, so that shouldn't be a problem.
I you would like to make random results repeatable, then you may want to use Random with seed.
Rather than create a new Random() object each time you want a new random number, just create the Random object once per run, and use the Random.nextInt() object once per run.
Looking at the documentation of Random() constructor,
This constructor sets the seed of the random number generator to a
value very likely to be distinct from any other invocation of this
constructor.it only guarantees it to be different
that's a bit of a weaker contract than the number you get from nextInt().
If you want to get the same sequence of numbers on each run, use the Random(long seed) or the setSeed(long seed) method of the random object. Both these methods set the seed of the generator. If you used the same seed for each invocation it's guaranteed that you will get the same sequence of numbers from the generator.
Random.setSeed(long).

Error with calendar class and generating numbers

I'm trying to do random number generation using the given date to create good pseudo-random numbers in Java. I decided to use the Calendar class and to count milliseconds in the day. This worked to some extent, but I can only get a different random value when I start the program. Running it any more times in the program will just give me the same number. I'm using Thread.sleep() to make sure that there is an actual difference on time, but I still get the same numbers.
Heres my method that I'm calling (from another class)
public long genRNG()
{
long mask = 0xFFFF000000000000L;
long randomValue = seed & mask;
seed = 0x5D588B656C078965L * cal.get(Calendar.MILLISECOND) + 0x0000000000269EC3;
return randomValue;
}
and here's my main method
public static void main(String[] args) throws InterruptedException
{
Seed key = new Seed();
for (int x = 0; x <=10; x++)
{
Thread.sleep(200);
System.out.println(key.genRNG());
}
}
and the given output:
-7389844038561562624
-7389844038561562624
-7389844038561562624
-7389844038561562624
-7389844038561562624
-7389844038561562624
-7389844038561562624
-7389844038561562624
-7389844038561562624
It seems you are setting mask to the same value each time and seed to the same value each time, so seed & mask yields the same value each time. A Calendar object does not automatically change its value after it has been instantiated — in other words it keeps the time it got when you constructed it (typically the time when it was constructed) until you explicitly change it. So one suggestion is to do reinitialize cal in each call to genRNG().
Here I have changed cal to a local variable:
long mask = 0xFFFF000000000000L;
long randomValue = seed & mask;
Calendar cal = Calendar.getInstance();
seed = 0x5D588B656C078965L * cal.get(Calendar.MILLISECOND) + 0x0000000000269EC3;
return randomValue;
Now I can get output like:
0
8430738502437568512
-2453898846963499008
2916080758722396160
3291568377654411264
-1326873040214032384
-951385421282017280
1212312724692795392
-3406128693175648256
-1298444067566256128
-5916885485434699776
The initial 0 comes from seed not having been initialized. I gather it’s not a problem in your code.
I don’t think you’re there yet, though. Calendar.get(Calendar.MILLISECOND) always returns a value in the interval 0 through 999, so you are getting up to 1000 different “random” values. Not a lot for storing in a long. You may get more for instance like this:
seed = 0x5D588B656C078965L * System.currentTimeMillis() + 0x0000000000269EC3;
If for some reason you want an object for the current time rather than just the long you get from System.currentTimeMillis(), if you can use Java 8, I suggest Instant.now().toEpochMilli(). It gives you the same long value, but Instant.now() gives you an object representing the current time, much like Calendar.getInstance(), only more modern and more versatile if you want to use it for other purposes.
Another issue is because of the mask your value will always end in 48 zeroes in binary representation (it’s easy to see all the values are even). Maybe this is as designed?
Also I suppose there is a reason why you are not just using java.util.Random.

How to create user friendly unique IDs, UUIDs or other unique identifiers in Java

I usually use the UUID class to generate unique IDs. This works fine if these IDs are used by technical systems only, they don't care how long they are:
System.out.println(UUID.randomUUID().toString());
> 67849f28-c0af-46c7-8421-94f0642e5d4d
Is there a nice way to create user friendly unique IDs (like those from tinyurl) which are a bit shorter than the UUIDs? Usecase: you want to send out IDs via Mail to your customers which in turn visit your site and enter that number into a form, like a voucher ID.
I assume that UUIDs get generated equally through the whole range of the 128 Bit range of the UUID. So would it be sage to use just the lower 64 Bits for instance?
System.out.println(UUID.randomUUID().getLeastSignificantBits());
Any feedback is welcome.
I assume that UUIDs get generated
equally through the whole range of the
128 Bit range of the UUID.
First off, your assumption may be incorrect, depending on the UUID type (1, 2, 3, or 4). From the Java UUID docs:
There exist different variants of
these global identifiers. The methods
of this class are for manipulating the
Leach-Salz variant, although the
constructors allow the creation of any
variant of UUID (described below).
The layout of a variant 2 (Leach-Salz)
UUID is as follows: The most
significant long consists of the
following unsigned fields:
0xFFFFFFFF00000000 time_low
0x00000000FFFF0000 time_mid
0x000000000000F000 version
0x0000000000000FFF time_hi
The least significant long consists of
the following unsigned fields:
0xC000000000000000 variant
0x3FFF000000000000 clock_seq
0x0000FFFFFFFFFFFF node
The variant field contains a value
which identifies the layout of the
UUID. The bit layout described above
is valid only for a UUID with a
variant value of 2, which indicates
the Leach-Salz variant.
The version field holds a value that
describes the type of this UUID. There
are four different basic types of
UUIDs: time-based, DCE security,
name-based, and randomly generated
UUIDs. These types have a version
value of 1, 2, 3 and 4, respectively.
The best way to do what you're doing is to generate a random string with code that looks something like this (source):
public class RandomString {
public static String randomstring(int lo, int hi){
int n = rand(lo, hi);
byte b[] = new byte[n];
for (int i = 0; i < n; i++)
b[i] = (byte)rand('a', 'z');
return new String(b, 0);
}
private static int rand(int lo, int hi){
java.util.Random rn = new java.util.Random();
int n = hi - lo + 1;
int i = rn.nextInt(n);
if (i < 0)
i = -i;
return lo + i;
}
public static String randomstring(){
return randomstring(5, 25);
}
/**
* #param args
*/
public static void main(String[] args) {
System.out.println(randomstring());
}
}
If you're incredibly worried about collisions or something, I suggest you base64 encode your UUID which should cut down on its size.
Moral of the story: don't rely on individual parts of UUIDs as they are holistically designed. If you do need to rely on individual parts of a UUID, make sure you familiarize yourself with the particular UUID type and implementation.
Here is another approach for generating user friendly IDs:
http://thedailywtf.com/Articles/The-Automated-Curse-Generator.aspx
(But you should go for the bad-word-filter)
Any UUID/Guid is just 16 Bytes of data. These 16 bytes can be easily encoded using BASE64 (or BASE64url), then stripped off all of the "=" characters at the end of the string.
This gives a nice, short string which still holds the same data as the UUID/Guid. In other words, it is possible to recreate the UUID/Guid from that data if such becomes necessary.
Here's a way to generate a URL-friendly 22-character UUID
public static String generateShortUuid() {
UUID uuid = UUID.randomUUID();
long lsb = uuid.getLeastSignificantBits();
long msb = uuid.getMostSignificantBits();
byte[] uuidBytes = ByteBuffer.allocate(16).putLong(msb).putLong(lsb).array();
// Strip down the '==' at the end and make it url friendly
return Base64.encode(uuidBytes)
.substring(0, 22)
.replace("/", "_")
.replace("+", "-");
}
For your use-case, it would be better to track a running count of registered user, and for each value, generate a string-token like this:
public static String longToReverseBase62(long value /* must be positive! */) {
final char[] LETTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
StringBuilder result = new StringBuilder(9);
do {
result.append(LETTERS[(int)(value % 62)]);
value /= 62l;
}
while (value != 0);
return result.toString();
}
For security reasons, it would be better if you make the values non-sequential, so each time a user registers, you can increment the value let's say by 1024 (This would be good to generate uuids for 2^64 / 2^10 = 2^54 users which is quite certainly more than you'd ever need :)
At the time of this writing, this question's title is:
How to create user friendly unique IDs, UUIDs or other unique identifiers in Java
The question of generating a user-friendly ID is a subjective one. If you have a unique value, there are many ways to format it into a "user-friendly" one, and they all come down to mapping unique values one-to-one with "user-friendly" IDs — if the input value was unique, the "user-friendly" ID will likewise be unique.
In addition, it's not possible in general to create a random value that's also unique, at least if each random value is generated independently of any other. In addition, there are many things you should ask yourself if you want to generate unique identifiers (which come from my section on unique random identifiers):
Can the application easily check identifiers for uniqueness within the desired scope and range (e.g., check whether a file or database record with that identifier already exists)?
Can the application tolerate the risk of generating the same identifier for different resources?
Do identifiers have to be hard to guess, be simply "random-looking", or be neither?
Do identifiers have to be typed in or otherwise relayed by end users?
Is the resource an identifier identifies available to anyone who knows that identifier (even without being logged in or authorized in some way)?
Do identifiers have to be memorable?
In your case, you have several conflicting goals: You want identifiers that are unique, random, and easy to type by end users. But other things you should think about are:
Are other users allowed to access the resource identified by the ID, whenever they know the ID? If not, then additional access control or a longer key length will be necessary.
Can your application tolerate the risk of duplicate keys? If so, then the keys can be completely randomly generated (such as by a cryptographic RNG such as java.security.SecureRandom in Java). If not, then your goal will be harder to achieve, especially for keys intended for security purposes.
Also, if you want IDs that have to be typed in by end users, you should consider choosing a character set carefully or allowing typing mistakes to be detected.
Only for you :) :
private final static char[] idchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
private static String createId(int len) {
char[] id = new char[len];
Random r = new Random(System.currentTimeMillis());
for (int i = 0; i < len; i++) {
id[i] = idchars[r.nextInt(idchars.length)];
}
return new String(id);
}
How about this one? Actually, this code returns 13 characters(numbers and lowercase alphabets) max.
import java.nio.ByteBuffer;
import java.util.UUID;
/**
* Generate short UUID (13 characters)
*
* #return short UUID
*/
public static String shortUUID() {
UUID uuid = UUID.randomUUID();
long l = ByteBuffer.wrap(uuid.toString().getBytes()).getLong();
return Long.toString(l, Character.MAX_RADIX);
}

Categories