Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
generate random UUIDs

UUID

Returns a random v4 UUID of the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, where each x is replaced with a random hexadecimal digit from 0 to f, and y is replaced with a random hexadecimal digit from 8 to b.

There's also @LeverOne's approach using iteration, which is one byte shorter.

function b(
a // placeholder
){
return a // if the placeholder was passed, return
? ( // a random number from 0 to 15
a ^ // unless b is 8,
Math.random() // in which case
* 16 // a random number from
>> a/4 // 8 to 11
).toString(16) // in hexadecimal
: ( // or otherwise a concatenated string:
[1e7] + // 10000000 +
-1e3 + // -1000 +
-4e3 + // -4000 +
-8e3 + // -80000000 +
-1e11 // -100000000000,
).replace( // replacing
/[018]/g, // zeroes, ones, and eights with
b // random hex digits
)
}
function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2011 Jed Schmidt <http://jed.is>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
{
"name": "UUID",
"description": "Generates random UUIDs",
"keywords": [
"UUID",
"ID",
"random"
]
}
@subzey

This comment has been minimized.

Copy link

@subzey subzey commented Aug 12, 2011

We can use coercion and exponential notation to get template string and save 7 bytes:
function(){return(""+1e7+-1e3+-4e3+-8e3+-1e11).replace(/1|0/g,function(){return(0|Math.random()*16).toString(16)})}

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Aug 13, 2011

subzey, you are a genius. fixing and annotating now.

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Aug 13, 2011

you also inspired me to cut 10 more bytes out:

function b(a){return a?(0|Math.random()*16).toString(16):(""+1e7+-1e3+-4e3+-8e3+-1e11).replace(/1|0/g,b)}
@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Aug 13, 2011

(0|Math.random()*16).toString(16)

can also be trimmed 4 bytes to

Math.random().toString(16)[2]

if you don't care about IE... thoughts?

@subzey

This comment has been minimized.

Copy link

@subzey subzey commented Aug 13, 2011

@jed, Math.random() may return 0, so Math.random().toString(16)[2] may return undefined.

Also, isn't setting name of function affects the outer scope?

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Aug 13, 2011

well, with the chance of Math.random returning a zero 1 in 2<<61, seems like the definition of an edge case. more likely that IE barfs on it.

also, we're allowing named functions because we assume that they'll be assigned externally.

@subzey

This comment has been minimized.

Copy link

@subzey subzey commented Aug 13, 2011

@jed, thanks for your clarification about function names, I didn't know that

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Aug 15, 2011

@subzey, i hope you use this knowledge to bring us some awesome new stuff.

@LeverOne

This comment has been minimized.

Copy link

@LeverOne LeverOne commented Oct 6, 2011

""+1e7+-1e3+-4e3+-8e3+-1e11 --> [1e7]+-1e3+-4e3+-8e3+-1e11
it's а flaw of many of you.

@subzey

This comment has been minimized.

Copy link

@subzey subzey commented Oct 7, 2011

@LeverOne, perfect! Thanks

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Oct 7, 2011

wow, that's crazy. good work @LeverOne.

@fgnass

This comment has been minimized.

Copy link

@fgnass fgnass commented Oct 7, 2011

What about replacing /1|0/ with /\d/?

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Oct 7, 2011

the 4 is hardcoded according to the spec, and the 8 is a bit of a hack... technically it should be anything from 8 to b. so replacing those would make it less compliant.

@fgnass

This comment has been minimized.

Copy link

@fgnass fgnass commented Oct 7, 2011

Ah I see, I missed that.

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Oct 7, 2011

i wonder if we finally have enough bytes to make it compliant, such that the 8 can be 8, 9, a, or b...

@subzey

This comment has been minimized.

Copy link

@subzey subzey commented Oct 7, 2011

It is enough already :)

function c(a,b){return a?(~~b+0|Math.random()*16>>b/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/1|0|(8)/g,c)}
@subzey

This comment has been minimized.

Copy link

@subzey subzey commented Oct 7, 2011

Or this, shorter:

function c(a,b){return a?(b|Math.random()*16>>b/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/1|0|(8)/g,c)}
@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Oct 7, 2011

thanks again, @subzey. updated.

@broofa

This comment has been minimized.

Copy link

@broofa broofa commented Oct 7, 2011

Line 20 of annotated.js should be 'c', not 'b'.

BTW, you're all insane. I love it! :)

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Oct 7, 2011

good catch! for those not in the know, @broofa is a celebrity in the world of UUIDs: https://github.com/broofa/node-uuid

@tsaniel

This comment has been minimized.

Copy link

@tsaniel tsaniel commented Oct 9, 2011

Maybe save 4 bytes...?


@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Oct 9, 2011

what the... how on earth does this work?

@tsaniel

This comment has been minimized.

Copy link

@tsaniel tsaniel commented Oct 9, 2011

There are three possible values 0,1,8 for a.

For case 0: 0^Math.random()*16>>0/4, >>0/4 is actually >>0, just works as Math.floor.
The 0^ here does nothing.

For case 1: 1^Math.random()*16>>1/4, >>1/4 is still >>0.
Although 1^ here toggles the least significant bit, we can still use it to generate random numbers 0-15.

For case 8: 8^Math.random()*16>>8/4, >>8/4 turns out >>2.
The maximum number of Math.random()*16 in binary form is 1111, that means the range is 0000-1111.
By right shifting 2 bits, the maximum number of Math.random()*16>>2 is 0011, and the range, 0000-0011. What it does here is to generate random numbers 0-3.
Finally, because the most significant bit is always 0, 8^ is actually 8|, it is to ensure the range starts from 8. And now we get 8 + {0, 1, 2, 3}.

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Oct 9, 2011

incredible work, @tsaniel!

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Oct 9, 2011

it's amazing how this gist has evolved, from

function(){return"00000000-0000-4000-8000-000000000000".replace(/0/g,function(){return(0|Math.random()*16).toString(16)})}

to

function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}

while hitting all the greatest hits: recursion, coercion of a number into a string through an array (!), operator repurposing...

@tsaniel

This comment has been minimized.

Copy link

@tsaniel tsaniel commented Oct 9, 2011

I love those tricks, especially the string coercion with array, though i love bitwise tricks.
By the way, i am still thinking if we can shorten /[018]/...

@atk

This comment has been minimized.

Copy link

@atk atk commented Oct 9, 2011

@tsaniel - no way, the other way round would be /[^4-]/, which is just as long.

@tsaniel

This comment has been minimized.

Copy link

@tsaniel tsaniel commented Oct 9, 2011

@atk: That's true. I mean if we can do something to use /\d/ instead.

@atk

This comment has been minimized.

Copy link

@atk atk commented Oct 9, 2011

...which would require that the 4 will be left alone and enlarge the equation probably more than the 3 letters we saved.

@tsaniel

This comment has been minimized.

Copy link

@tsaniel tsaniel commented Oct 9, 2011

Maybe that's the end.

@atk

This comment has been minimized.

Copy link

@atk atk commented Oct 9, 2011

I fear it is.

@subzey

This comment has been minimized.

Copy link

@subzey subzey commented Oct 11, 2011

Once again, excellent work, @tsaniel!

Sorry for my late comment, my mobile browser doesn't work well with github

@LeverOne

This comment has been minimized.

Copy link

@LeverOne LeverOne commented Oct 24, 2011

Recursion & coercion vs. loop & math: https://gist.github.com/1308368

@jed

This comment has been minimized.

Copy link
Owner Author

@jed jed commented Oct 24, 2011

just when you thought it couldn't get any shorter, @LeverOne sheds a byte. good job!

@tsaniel

This comment has been minimized.

Copy link

@tsaniel tsaniel commented Oct 24, 2011

@LeverOne is my hero.

@kalupa

This comment has been minimized.

Copy link

@kalupa kalupa commented Jun 20, 2013

damnit jed, i keep finding you everywhere. thanks for this!

@jussi-kalliokoski

This comment has been minimized.

Copy link

@jussi-kalliokoski jussi-kalliokoski commented Jun 27, 2013

In Firefox you could use the single statement function body to shorten it a few bits still:

function b(a)a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)
@jussi-kalliokoski

This comment has been minimized.

Copy link

@jussi-kalliokoski jussi-kalliokoski commented Jun 27, 2013

Shorter yet (cheats, ES6, and works only in Firefox!!!), and less leaky:

function()([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,a=>(a^Math.random()*16>>a/4).toString(16))
@jussi-kalliokoski

This comment has been minimized.

Copy link

@jussi-kalliokoski jussi-kalliokoski commented Jun 27, 2013

Hah, since I already used ES6 and there are no variable assignments, might as well go all the way and avoid Firefox-only stuff:

()=>([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,a=>(a^Math.random()*16>>a/4).toString(16))
@jameswyse

This comment has been minimized.

Copy link

@jameswyse jameswyse commented Jul 29, 2013

This is awesome!

Here's a benchmark vs node-uuid: http://jsperf.com/node-uuid-performance/11

@ronkorving

This comment has been minimized.

Copy link

@ronkorving ronkorving commented Aug 22, 2013

I was so rooting for Crazy Gist to win that one :(

@thelinuxlich

This comment has been minimized.

Copy link

@thelinuxlich thelinuxlich commented Oct 24, 2015

Is this relatively safe to generate UUIDs simultaneously between many clients?

@coolaj86

This comment has been minimized.

Copy link

@coolaj86 coolaj86 commented Nov 8, 2015

Make it secure at the cost of just a few bytes by replacing Math.random() * 16:

browser

crypto.getRandomValues(new Uint8Array(1))[0] % 16

function b(
  a                  // placeholder
){
  return a           // if the placeholder was passed, return
    ? (              // a random number from 0 to 15
      a ^            // unless b is 8,
      crypto.getRandomValues(new Uint8Array(1))[0]  // in which case
      % 16           // a random number from
      >> a/4         // 8 to 11
      ).toString(16) // in hexadecimal
    : (              // or otherwise a concatenated string:
      [1e7] +        // 10000000 +
      -1e3 +         // -1000 +
      -4e3 +         // -4000 +
      -8e3 +         // -80000000 +
      -1e11          // -100000000000,
      ).replace(     // replacing
        /[018]/g,    // zeroes, ones, and eights with
        b            // random hex digits
      )
}

node.js

crypto.randomBytes(1)[0] % 16

function b(
  a                  // placeholder
){
  return a           // if the placeholder was passed, return
    ? (              // a random number from 0 to 15
      a ^            // unless b is 8,
      crypto.randomBytes(1)[0]  // in which case
      % 16           // a random number from
      >> a/4         // 8 to 11
      ).toString(16) // in hexadecimal
    : (              // or otherwise a concatenated string:
      [1e7] +        // 10000000 +
      -1e3 +         // -1000 +
      -4e3 +         // -4000 +
      -8e3 +         // -80000000 +
      -1e11          // -100000000000,
      ).replace(     // replacing
        /[018]/g,    // zeroes, ones, and eights with
        b            // random hex digits
      )
}
@dalanmiller

This comment has been minimized.

Copy link

@dalanmiller dalanmiller commented Nov 10, 2015

@coolaj89 I don't have crypto.randomBytes in Chrome 46.0.2490.80 but there is crypto.getRandomValues

@aichholzer

This comment has been minimized.

Copy link

@aichholzer aichholzer commented Sep 5, 2016

And even smaller now:

b = a=>a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b);
@Kiodaddy

This comment has been minimized.

Copy link

@Kiodaddy Kiodaddy commented Jun 20, 2017

I am having issue in 3rd file and i am not able to correct it .

@GraniteConsultingReviews

This comment has been minimized.

Copy link

@GraniteConsultingReviews GraniteConsultingReviews commented Aug 27, 2017

Great This works well thanks

@fergusean

This comment has been minimized.

Copy link

@fergusean fergusean commented Aug 30, 2017

in the annotated version:

-8e3 +         // -80000000 +

should be

-8e3 +         // -8000 +
@GraniteConsultingReviews

This comment has been minimized.

Copy link

@GraniteConsultingReviews GraniteConsultingReviews commented Sep 7, 2017

I try this code but this is not generating random UUIDs

@Liath

This comment has been minimized.

Copy link

@Liath Liath commented Oct 23, 2017

@coolaj89's you can golf that down a little:
([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b=>(b^crypto.rng(1)[0]%16>>b/4).toString(16))
crypto.rng is the same as crypto.randomBytes on a stock node.js build.

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Nov 22, 2017

You guys are freaking insane...I love it...

@sowmitranalla

This comment has been minimized.

Copy link

@sowmitranalla sowmitranalla commented Dec 5, 2017

this was a wonderful thread to read

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Dec 23, 2017

@coolaj89 for the browser version you can shave off another char by replacing:

new Uint8Array(1)

with (not supported in all browsers, of course):

Uint8Array.of(0)
@Louies89

This comment has been minimized.

Copy link

@Louies89 Louies89 commented Jan 4, 2018

@jussi-kalliokoski
For Nodejs, below change has to be done:
()=>([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,a=>((a^crypto.randomBytes(1)[0]*16>>a/4).toString(16))[0])

@seanlindo

This comment has been minimized.

Copy link

@seanlindo seanlindo commented Mar 3, 2018

This is fantastic.

@Elephant-Vessel

This comment has been minimized.

Copy link

@Elephant-Vessel Elephant-Vessel commented Mar 7, 2018

Awesome. Is there a readable non-golfed version of this code?

@miniak

This comment has been minimized.

Copy link

@miniak miniak commented Mar 17, 2018

you can use this `${1e7}-${1e3}-${4e3}-${8e3}-${1e11}` to make it clear that it's a string

@mindplay-dk

This comment has been minimized.

Copy link

@mindplay-dk mindplay-dk commented Apr 6, 2018

Awesome. Is there a readable non-golfed version of this code?

Here's a more readable (verbose, RFC-compliant) version using crypto API:

var hex = [];

for (var i = 0; i < 256; i++) {
    hex[i] = (i < 16 ? '0' : '') + (i).toString(16);
}

function makeUUID() {
    var r = crypto.getRandomValues(new Uint8Array(16));

    r[6] = r[6] & 0x0f | 0x40;
    r[8] = r[8] & 0x3f | 0x80;

    return (
        hex[r[0]] +
        hex[r[1]] +
        hex[r[2]] +
        hex[r[3]] +
        "-" +
        hex[r[4]] +
        hex[r[5]] +
        "-" +
        hex[r[6]] +
        hex[r[7]] +
        "-" +
        hex[r[8]] +
        hex[r[9]] +
        "-" +
        hex[r[10]] +
        hex[r[11]] +
        hex[r[12]] +
        hex[r[13]] +
        hex[r[14]] +
        hex[r[15]]
    );
}
@MikeFielden

This comment has been minimized.

Copy link

@MikeFielden MikeFielden commented May 7, 2018

I have nothing excellent to offer other than I have REALLY enjoyed reading this :)

@pb-nati

This comment has been minimized.

Copy link

@pb-nati pb-nati commented May 17, 2018

This is amazing. Small piece of code to do something simple.

@PaulCordo

This comment has been minimized.

Copy link

@PaulCordo PaulCordo commented May 24, 2018

What's this [1e7] part for that Typescript refuse to compile saying "Operator '+' cannot be applied to types 'number[]' and '-1000'." ?

@AJamesPhillips

This comment has been minimized.

Copy link

@AJamesPhillips AJamesPhillips commented May 29, 2018

@PaulCordo it's because these insane(ly amazing) authors want to convert 1e7 into a string and because [1e7]+-1e3 is 1 byte shorter than ""+1e7+-1e3! :) A bit more info and an example: https://stackoverflow.com/q/9300941/539490

@eric1iu

This comment has been minimized.

Copy link

@eric1iu eric1iu commented Jun 15, 2018

wow! amazing!

@edo9k

This comment has been minimized.

Copy link

@edo9k edo9k commented Jul 6, 2018

NICE!

@dehghani-mehdi

This comment has been minimized.

Copy link

@dehghani-mehdi dehghani-mehdi commented Jul 21, 2018

After reading comments, I figure out I don't nothing about JS, really great job, thank you !!

@faazshift

This comment has been minimized.

Copy link

@faazshift faazshift commented Jul 28, 2018

I came here from the link in the README of kelektiv/node-uuid. I've tested v4 of that implementation, including forcing it to use the non cryptographically safe Math.random() for random number generation, and found it to be pretty reliably unique over many millions of iterations. However, this mini UUID function pretty reliably runs into collisions after 20-30 million iterations. Not entirely sure what the design flaw is, but for UUIDs that need to be guaranteed unique, it's probably best not to use this function in its present form in mission-critical code. Other than that, nice work on creating such a compact ID generator.

@BerlinChan

This comment has been minimized.

Copy link

@BerlinChan BerlinChan commented Sep 19, 2018

I like this LICENSE! That is awosome and so easy to understand!

@handicraftsman

This comment has been minimized.

Copy link

@handicraftsman handicraftsman commented Sep 25, 2018

Lol

@LDubya

This comment has been minimized.

Copy link

@LDubya LDubya commented Oct 29, 2018

Such collaboration. This is what the internet was made for.

@smurp

This comment has been minimized.

Copy link

@smurp smurp commented Nov 2, 2018

Who's reading this at 2018-11-02T09:07:56Z ?

@rmpel

This comment has been minimized.

Copy link

@rmpel rmpel commented Nov 9, 2018

I. F*KING. LOVE. THIS.

I would have NEVER EVER thought of doing this like this!

Amazing work!

@bengrunfeld

This comment has been minimized.

Copy link

@bengrunfeld bengrunfeld commented Jan 11, 2019

Just to save a few more characters. ;)

let b=a=>a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)

@daCyberpunk

This comment has been minimized.

Copy link

@daCyberpunk daCyberpunk commented Feb 3, 2019

Crazy guys! Awesome job! Lovely License! Thx

@Hypoon

This comment has been minimized.

Copy link

@Hypoon Hypoon commented Feb 7, 2019

First thing's first: I am not a lawyer, and I couldn't care less about the legal details anyway, but others might, SOOOO...

The copyright line in the license applies to the wording of the license. Unless you authored the license, it shouldn't be your copyright. Leaving it as-is constitutes (presumably accidental) plagiarism. Am I wrong?

See http://www.wtfpl.net/faq/ for details.

I doubt anybody cares much, but other people are forking this and updating the copyright line with their own names, thereby perpetuating the error.

(With that said, this is an awesome way to generate a UUID. Thank you for sharing!)

@variadico

This comment has been minimized.

Copy link

@variadico variadico commented Apr 7, 2019

What is the purpose of the placeholder function param a in function b(a)?

@Aaronius

This comment has been minimized.

Copy link

@Aaronius Aaronius commented Apr 10, 2019

I can confirm what @faazshift has said, which is a bit worrisome. In four consecutive runs of attempting to generate 50 million unique IDs, I ran into collisions after:

  1. 22342746 IDs generated
  2. 24863680 IDs generated
  3. 32720420 IDs generated
  4. 24487480 IDs generated

In every run, all IDs generated after the first collision occurred were also collisions. This is the script I used for testing:

function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}

const sets = [];

let currentSet;
let breakAtIndex;

for (let i = 0; i < 50000000; i++) {
  if (i % 1000000 === 0) {
    console.log(`${i} IDs generated`);
    // Generate a new set so that we don't run into max size limits
    currentSet = new Set();
    sets.push(currentSet);
  }

  const id = b();
  if (sets.find(set => set.has(id))) {
    console.log(`Conflict: ${id} at index ${i}`);

    if (!breakAtIndex) {
      breakAtIndex = i + 10;
    }
  }

  if (breakAtIndex === i) {
    break;
  }

  currentSet.add(id);
}

console.log("Done");
@standardizer

This comment has been minimized.

Copy link

@standardizer standardizer commented Jul 16, 2019

I can confirm what @faazshift has said, which is a bit worrisome. In four consecutive runs of attempting to generate 50 million unique IDs, I ran into collisions after:

  1. 22342746 IDs generated
  2. 24863680 IDs generated
  3. 32720420 IDs generated
  4. 24487480 IDs generated

In every run, all IDs generated after the first collision occurred were also collisions. This is the script I used for testing:

function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}

const sets = [];

let currentSet;
let breakAtIndex;

for (let i = 0; i < 50000000; i++) {
  if (i % 1000000 === 0) {
    console.log(`${i} IDs generated`);
    // Generate a new set so that we don't run into max size limits
    currentSet = new Set();
    sets.push(currentSet);
  }

  const id = b();
  if (sets.find(set => set.has(id))) {
    console.log(`Conflict: ${id} at index ${i}`);

    if (!breakAtIndex) {
      breakAtIndex = i + 10;
    }
  }

  if (breakAtIndex === i) {
    break;
  }

  currentSet.add(id);
}

console.log("Done");

@faazshift and @Aaronius, which browser did you run the script in?
Using Firefox Version 68.0 (64 Bit) on Windows 10 Version 1903 (64 Bit), I created more than 65 Million UUIDs without any collision.
The function b() seem fine for me, so Math.random() must have been the culprit.

@Aaronius

This comment has been minimized.

Copy link

@Aaronius Aaronius commented Jul 16, 2019

Chrome on Mac Mojave. I don't remember which version of Chrome, but it would have been a recent one.

@Aaronius

This comment has been minimized.

Copy link

@Aaronius Aaronius commented Jul 16, 2019

I just tried again on the following:

Chrome 75.0.3770.100 (64 bit)
Safari 12.0 (14606.1.36.1.9)
Firefox 67.0.4 (64 bit)

all on Mac Mojave OS. I was able to successfully generate 50 million unique IDs on all of them. I'm not sure what changed, but that's good news!

@faazshift

This comment has been minimized.

Copy link

@faazshift faazshift commented Jul 16, 2019

@standardizer Node.js, but I validated the collision in Chrome on linux. I just reproduced the collision in the latest version of Node.js.

@standardizer

This comment has been minimized.

Copy link

@standardizer standardizer commented Jul 17, 2019

@standardizer Node.js, but I validated the collision in Chrome on linux. I just reproduced the collision in the latest version of Node.js.

@faazshift You wrote, you found it [the Math.random() return value] to be pretty reliably unique over many millions of iterations. Could you provide your test script, please?

@faazshift

This comment has been minimized.

Copy link

@faazshift faazshift commented Jul 17, 2019

@standardizer In my original comment, I was referring to v4 of the uuid package available via npm. That package contains a link to this gist.

In my test case back when I made that determination, I used a copied and pared down version of this:

https://github.com/kelektiv/node-uuid/blob/master/v4.js

By using Math.random() for random number generation, I was referring to using this in my pared down test code:

https://github.com/kelektiv/node-uuid/blob/master/lib/rng-browser.js#L26-L33

@saileshkotha

This comment has been minimized.

Copy link

@saileshkotha saileshkotha commented Sep 9, 2019

I just tried again on the following:

Chrome 75.0.3770.100 (64 bit)
Safari 12.0 (14606.1.36.1.9)
Firefox 67.0.4 (64 bit)

all on Mac Mojave OS. I was able to successfully generate 50 million unique IDs on all of them. I'm not sure what changed, but that's good news!

Can you please post your test code, thanks

@Aaronius

This comment has been minimized.

Copy link

@Aaronius Aaronius commented Sep 9, 2019

I used the same test code that I posted previously in https://gist.github.com/jed/982883#gistcomment-2886092

@RobertoMachorro

This comment has been minimized.

Copy link

@RobertoMachorro RobertoMachorro commented Oct 4, 2019

This gist is beautiful, enlightening, entertaining and brilliant!

@lxghtless

This comment has been minimized.

Copy link

@lxghtless lxghtless commented Oct 14, 2019

👍 for best license ever.

@davimello28

This comment has been minimized.

Copy link

@davimello28 davimello28 commented Oct 18, 2019

This piece of nice code made my day better. I spent some nice minutes going through comments. Thank you!

@taylorjdawson

This comment has been minimized.

Copy link

@taylorjdawson taylorjdawson commented Oct 31, 2019

Someone should make a v5 deterministic UUID version!

@AdamRGrey

This comment has been minimized.

Copy link

@AdamRGrey AdamRGrey commented Nov 24, 2019

@mindplay-dk Can I use that?

@kizerkizer

This comment has been minimized.

Copy link

@kizerkizer kizerkizer commented Nov 24, 2019

Who's reading this at 2018-11-02T09:07:56Z ?

[2019 CReW RePoRTiNG iN] ~~ like if you're still watching this epic gist in 2019 ~~ [2019 CReW RePoRTiNG iN]

Also, any resolution to the latest collision issues? Are people using this in production?

Beautiful snippet, btw.

@mindplay-dk

This comment has been minimized.

Copy link

@mindplay-dk mindplay-dk commented Nov 24, 2019

@AdamRGrey of course 😊

@RobertoMachorro

This comment has been minimized.

Copy link

@RobertoMachorro RobertoMachorro commented Nov 24, 2019

Who's reading this at 2018-11-02T09:07:56Z ?

[2019 CReW RePoRTiNG iN] ~~ like if you're still watching this epic gist in 2019 ~~ [2019 CReW RePoRTiNG iN]

Also, any resolution to the latest collision issues? Are people using this in production?

Beautiful snippet, btw.

Using this in production, several projects, no collisions yet. I've considered changing that Math.random to something Date.now() based if it does happen, but if it ain't broke...

@AndrWeisR

This comment has been minimized.

Copy link

@AndrWeisR AndrWeisR commented Dec 5, 2019

This gist is a good example of the "Look at me, I'm a genius programmer who is so smart I can write unmaintainable code" disease.

@mindplay-dk

This comment has been minimized.

Copy link

@mindplay-dk mindplay-dk commented Dec 6, 2019

@AndrWeisR code golfing is harmless fun and a useful exercise that teaches you the details of the language. Would I put this in a project when I'm trying to collaborate with others? of course not, but golfing isn't just "genius programmers showing off", it's also just programmers challenging each other to practice, improve and have 𝒇𝒖𝒏™. 🙃

@Aaronius

This comment has been minimized.

Copy link

@Aaronius Aaronius commented Dec 6, 2019

A UUID generator is frequently treated as a black box by those who use one anyway. For such people, they'd rather have a black box with less code rather than a black box with more code, even if the code was the product of a nerdy online challenge. 🤷‍♂️

@sapher

This comment has been minimized.

Copy link

@sapher sapher commented Dec 14, 2019

This gist is a good example of the "Look at me, I'm a genius programmer who is so smart I can write unmaintainable code" disease.

Look at me "I'm jealous" disease. Take it as a challenge. It's just a gist, chill.

@PatrickDuncan

This comment has been minimized.

Copy link

@PatrickDuncan PatrickDuncan commented Dec 30, 2019

Thank you for this. This is what I had to do for: TypeScript + ESLint

const getUuid = (a: string = ''): string => (
  a
    /* eslint-disable no-bitwise */
    ? ((Number(a) ^ Math.random() * 16) >> Number(a) / 4).toString(16)
    : (`${1e7}-${1e3}-${4e3}-${8e3}-${1e11}`).replace(/[018]/g, getUuid)
);
getUuid();
@webdeb

This comment has been minimized.

Copy link

@webdeb webdeb commented Jan 8, 2020

finally I found a place to learn some code 👍

@luminarious

This comment has been minimized.

Copy link

@luminarious luminarious commented Jan 18, 2020

Here's UUID v1. Doesn't fit in tweet 😒

// http://www.rfcreader.com/#rfc4122_line385 allows random instead of MAC address
// https://www.famkruithof.net/uuid/uuidgen
// https://realityripple.com/Tools/UnUUID/

// TODO: Refactor into generator function, so random clock ID stays uniform for the lifetime of application instance?
function uuid(c = 9999) {
  const t = ((Date.now() + 12219292800000) * 1E4).toString(16)
  const n = crypto.getRandomValues(new Uint8Array(6)).reduce((sum, x, i) => {
    return sum + ((i === 0) ? x|1 : x).toString(16).padStart(2, '0')
  }, '')

  return `${t.slice(-8)}-${t.slice(-12, -8)}-1${t.slice(0, 3)}-${c}-${n}`
}

// Give me some examples
for (let i = 100; i--; console.log(uuid())) {}
@jsejcksn

This comment has been minimized.

Copy link

@jsejcksn jsejcksn commented Mar 22, 2020

Here's an ES-updated take on @mindplay-dk's non-golf version:

const uuidv4 = () => {
  const hex = [...Array(256).keys()]
    .map(index => (index).toString(16).padStart(2, '0'));

  const r = crypto.getRandomValues(new Uint8Array(16));

  r[6] = (r[6] & 0x0f) | 0x40;
  r[8] = (r[8] & 0x3f) | 0x80;
  
  return [...r.entries()]
    .map(([index, int]) => [4, 6, 8, 10].includes(index) ? `-${hex[int]}` : hex[int])
    .join('');
};

Has anyone written a version which doesn't use bitwise operators?

@mindplay-dk

This comment has been minimized.

Copy link

@mindplay-dk mindplay-dk commented Mar 24, 2020

@jsejcksn you probably should hoist your hex table to the parent scope, to avoid recalculating every time. Also note (though you might not care, depending on your use-case) that I was deliberately avoiding loops in my version for performance reasons - using map makes for fewer lines, but much slower execution. 🙂

@jsejcksn

This comment has been minimized.

Copy link

@jsejcksn jsejcksn commented Mar 24, 2020

@mindplay-dk Thanks, it’s primarily for readability.

For max optimization, one of the other golfed versions could be used, or you could compile your code using an optimizing transpiler.

@dbones0527

This comment has been minimized.

Copy link

@dbones0527 dbones0527 commented Apr 18, 2020

We can use coercion and exponential notation to get template string and save 7 bytes:
function(){return(""+1e7+-1e3+-4e3+-8e3+-1e11).replace(/1|0/g,function(){return(0|Math.random()*16).toString(16)})}

@ ### #

@haeric

This comment has been minimized.

Copy link

@haeric haeric commented Aug 1, 2020

We have been using this in production on the web, and are seeing a lot of collisions with the versions using Math.random in certain browsers. If you are using any of these snippets on the web, definitely use one that uses crypto.getRandomValues! Even if you tested it on your system and did not see any collisions, some other system/browser combination may implement Math.random in a way that causes easy collisions.

@chris-kruining

This comment has been minimized.

Copy link

@chris-kruining chris-kruining commented Oct 8, 2020

It has been a huge treat to read this thread, so much positivity, creativity, knowledge and collaboration!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.