2010-02-11 22 views
9

Quando un utente aggiunge un nuovo elemento nel mio sistema, voglio produrre un codice pseudo-casuale a 7 cifre non incrementale unico per quell'elemento. Il numero di elementi creati sarà numerato solo in migliaia (< 10.000).Come posso creare un codice univoco a 7 cifre per un'entità?

Perché ha bisogno di essere unico e non ci sono due elementi con le stesse informazioni, potrei usare un hash, ma deve essere un codice che possono condividere con altre persone - da qui le 7 cifre.

Il mio pensiero originale era solo quello di ripetere la generazione di un numero casuale, controllare che non fosse già utilizzato, e se lo fosse, risciacquare e ripetere. Penso che questa sia una soluzione ragionevole, anche se sgradevole, data la bassa probabilità di collisioni.

Le risposte a this question suggeriscono di generare un elenco di tutti i numeri non utilizzati e di mischiarli. Probabilmente potrei tenere una lista come questa in un database, ma stiamo parlando di 10.000.000 di voci per qualcosa di relativamente poco frequente.

Qualcuno ha un modo migliore?

+12

'statico int i = 9999999; int get_non_increasing_unique_code (void) {return i -;}' – kennytm

+0

@Kenny: Ha ha ha ... –

+0

@Kenny: +1 per farmi ridere :) – Damovisa

risposta

15

Pick a 7 cifre primo numero A, e un grande primo numero B, e

int nth_unique_7_digit_code(int n) { 
    return (n * B) % A; 
} 

Il conteggio di tutti i codici univoci generati da questo sarà A .

Se si vuole essere più "sicura", fare pow(some_prime_number, n) % A, vale a dire

static int current_code = B; 
int get_next_unique_code() { 
    current_code = (B * current_code) % A; 
    return current_code; 
} 
+0

Hai qualche informazione di base sul perché questo funziona? – spoulson

+0

Non sono completamente sicuro di cosa stia facendo, ma sembra vagamente simile alla parte importante dell'algoritmo RSA. Credo. – rmeador

+0

Non c'è alcun punto nel scegliere un B più grande di A. –

2

suggerirei di utilizzare un guid invece di un codice a 7 cifre in quanto sarà più unico e non dovrete preoccuparvi di generarli come .NET lo farà per voi.

+0

'System.Guid.NewGuid();' – harryovers

+4

Ha detto che le persone devono condividere questo numero con altre persone. I GUID non sono ... dovremmo dire ... * ideale * ... per questo scopo. –

+0

Sì, esattamente. Per un po 'più di background, questo è essenzialmente un "gruppo" a cui le persone possono aderire. È difficile dire alle persone di unirsi al gruppo a53df3d0-171f-11df-8a39-0800200c9a66. – Damovisa

4

Onestamente, se si desidera generare solo un paio di migliaia di codici a 7 cifre, mentre 10 milioni di codici diversi saranno disponibili, penso che ne generi uno casuale e il controllo di una collisione sia sufficiente.

La possibilità di una collisione sul primo colpo sarà, nel peggiore dei casi, circa 1 su mille, e lo sforzo computazionale per generare solo un nuovo codice a 7 cifre e verificare nuovamente la collisione sarà molto più piccolo di un dizionario o soluzioni simili.

Utilizzare un GUID invece di un codice a 7 cifre come suggerito anche da harryovers, ma ovviamente un GUID sarà leggermente più difficile da ricordare per gli utenti.

+0

Anche se in realtà è improbabile che accada, non dimenticare mai che l'effettivo scenario peggiore per generare in questo modo è infinito. –

+0

@Robin, fortunatamente anche la possibilità di farlo è infinitamente piccola :) – Aistina

2

Tutte le soluzioni per un ID "univoco" devono avere un database da qualche parte: uno che contiene gli ID utilizzati o uno con gli ID gratuiti. Come hai notato, il database con ID gratuiti sarà abbastanza grande, quindi la maggior parte delle volte le persone usano un database "ID usato" e controllano le collisioni.

Detto questo, alcuni database offrono un generatore/sequenza "ID casuale" che restituisce già gli ID in un intervallo in ordine casuale.

Questo funziona utilizzando un generatore di numeri casuali che può creare tutti i numeri in un intervallo senza ripetersi oltre alla funzione che è possibile salvare lo stato in qualche punto. Quindi quello che fai è eseguire il generatore una volta, utilizzare l'ID e salvare il nuovo stato. Per la prossima esecuzione, si carica lo stato e si reimposta il generatore sull'ultimo stato per ottenere il successivo ID casuale.

+0

Grazie, hai ragione, ovviamente - Dovrò memorizzare quell'ID "unica" da qualche parte. Avete ulteriori informazioni sui generatori di sequenze casuali del database? Attualmente sto utilizzando SQL Server Express 2008. – Damovisa

+0

@Damovisa: consulta la risposta di SideShowCoder relativa agli LFSR. –

5

È possibile utilizzare un ID incrementale e quindi XOR su una chiave fissa.

const int XORCode = 12345; 

private int Encode(int id) 
{ 
    return id^XORCode; 
} 

private int Decode(int code) 
{ 
    return code^XORCode; 
} 
+0

Dovrò indagare ulteriormente, ma sembra che potrebbe funzionare ... È ancora possibile ottenere gruppi di codici anche se non lo sei? – Damovisa

+0

Dipende dai tuoi id e dalla tua scelta di chiave. Poiché ti aspetti solo ~ 10000 elementi, dovresti essere in grado di giocare con i dati e vedere quale risultato ottieni. –

0

Con solo migliaia di elementi nel database, l'idea originale sembra valida. Il controllo dell'esistenza di un valore in un elenco ordinato (indicizzato) di alcune decine di migliaia di elementi richiederebbe solo alcuni recuperi e confronti di dati.

La pre-generazione dell'elenco non sembra una buona idea, perché memorizzerete più numeri del necessario, oppure dovrete gestire il tempo esaurito.

+0

Beh, ha solo sette cifre: ne uscirà allo stesso tempo, indipendentemente dal fatto che le memorizzi in un database o meno. :-) –

+0

In base alla domanda, è improbabile che utilizzi tutti i dieci milioni di numeri possibili. Pertanto, è uno spreco memorizzare tutti i dieci milioni. Quindi, quanti ne ha bisogno per archiviare? Anche centomila sprechi. Diecimila probabilmente non è abbastanza. Trovare il giusto equilibrio è un compromesso, e non mi sembra un buon piano per me. Preferisco le soluzioni che sono garantite per funzionare bene sotto tutti i potenziali scenari. –

2

Suppongo che tu abbia un tavolo del generato. In tal caso, non vedo alcun problema nel selezionare numeri casuali e nel controllarli rispetto al database, ma non lo farei singolarmente. Generarli è economico, fare la query DB è costoso rispetto a quello. Genererei 100 o 1.000 alla volta e poi chiedo al DB quale di questi esiste. Scommetti che non dovrai farlo due volte la maggior parte del tempo.

+0

Non è una cattiva idea ... – Damovisa

0

probabilità di avere colpi è molto bassa.
Ad esempio, si dispone di 10^4 utenti e 10^7 possibili ID.
Probabilità che si scelga l'ID utilizzato 10 volte di seguito è ora 10^-30.
Questa possibilità è inferiore a una volta nella vita di una persona.

+0

Ahem, paradosso del compleanno. – kennytm

+0

Non si applica qui. Dovrebbe aggiungere il codice per il controllo degli accessi, ma c'è una bassa probabilità che dovrà provare più di poche volte. –

2

Hai < 10.000 articoli, quindi sono necessarie solo 4 cifre per memorizzare un numero univoco per tutti gli articoli. Dato che hai 7 cifre, hai 3 cifre in più.

Se si combina un numero di sequenza univoco di 4 cifre con un numero casuale di 3 cifre, si sarà univoci e casuali. Si incrementa il numero di sequenza con ogni nuovo ID generato.

È possibile aggiungerli in qualsiasi ordine o mescolarli.

ss = abcd, RND = ABC

È possibile creare il successivo ID:

  • abcdABC
  • ABCabcd
  • aAbBcCd

Se si utilizza un solo miscelazione algoritmo, avrai numeri univoci, che sembrano casuali.

1

Vorrei provare a utilizzare un LFSR (registro di spostamento lineare di feedback) il codice è davvero semplice, è possibile trovare esempi ovunque cioè Wikipedia e anche se non è crittograficamente sicuro sembra molto casuale. Anche l'implementazione sarà molto veloce poiché utilizza principalmente le operazioni di cambio.

0

Bene, è potrebbe chiedere all'utente di scegliere il proprio numero di 7 cifre e convalidarlo contro la popolazione di numeri esistenti (che avresti memorizzato mentre erano esauriti), ma ho il sospetto che tu stia filtrando molte risposte di tipo 1234567, 7654321, 9999999, 7777777 e potrebbero essere necessarie alcune RegEx per ottenere il filtro, in più bisognerebbe avvisare l'utente di tali sequenze per non avere un'esperienza di input utente negativa e ripetitiva.

Problemi correlati