Combina sequenze di numeri con "bitlength variabili" in stringhe univoche corte

0

Non è improbabile che ciò che voglio fare non sia possibile, ma non fa male a chiedere.

Immaginate un insieme di liste, ciascuna contenente interi positivi (nel mio caso, una lista consiste sempre di quattro numeri interi, ma ciò non dovrebbe fare alcuna differenza).

a = [35, 2, 123684, 647]
b = [453, 346457546457, 6, 0]
c = ...

Poi c'è un alfabeto, per esempio

alphabet = [A, .., Z, a, .., z, 0, .., 9]

Quello che voglio fare è creare una funzione che trasformi gli elenchi in stringhe usando l'alfabeto.

f: (list[Int], alphabet) -> string 

I requisiti per f sono i seguenti:

  • f dovrebbe essere iniettivo, nel senso che due liste diverse portano sempre a due stringhe diverse e una lista specifica produce sempre la stessa stringa ogni volta che viene chiamato f.

    Note:

    • Due liste sono uguali se entrambe contengono gli stessi elementi nello stesso ordine.
    • Va bene se le trasformazioni di liste diverse che usano alfabeti diversi danno come risultato la stessa stringa. Il requisito univoco si applica solo alla trasformazione di elenchi diversi utilizzando lo stesso alfabeto.
    • Non è richiesta una funzione inversa.
  • Ora la parte difficile: le stringhe risultanti devono essere il più corte possibile.

Tutti i numeri sono interi a 32 bit. Ma il fatto che siano di dimensioni molto diverse (l'intervallo possibile va da 0 a Int.max ) dovrebbe essere preso in considerazione. Concatenare insieme le rappresentazioni a 32 bit (o fare qualcos'altro che usa pezzi di dimensioni fisse) non è una soluzione praticabile.

Un approccio potrebbe essere quello di scegliere un carattere dell'alfabeto e usarlo come separatore. Questo è fondamentalmente ciò che fanno gli hashids . Per esempio. se 'A' è il separatore, tutte le stringhe risultanti avranno questo aspetto: "...A...A...A..." .

Cosa non mi piace di questa soluzione:

  • La dimensione effettiva dell'alfabeto è ridotta di uno, poiché uno dei caratteri può essere usato solo come separatore, non per i numeri di codifica. Ciò si traduce in stringhe più lunghe, soprattutto quando si usano alfabeti piccoli
  • Anche il separatore estende la stringa. La codifica di un elenco di quattro numeri interi significa tre caratteri aggiuntivi nel risultato.

Mi chiedo se c'è una soluzione meno ovvia al problema, forse un approccio più matematico? In sostanza, il problema è "unire" più numeri in un unico numero (unico).

    
posta ceaaj 07.06.2016 - 01:54
fonte

1 risposta

0

Penso che Doc Brown abbia colto il vero problema: è un problema di compressione. In quanto tale, prima di tutto i numeri vengono convertiti in una rappresentazione binaria (bit compressi, un array di byte) e quindi la codifica mediante le lettere è probabilmente la soluzione migliore. Quando si esegue lo streaming su una rappresentazione binaria, includere la lunghezza di qualsiasi raccolta di dimensioni variabili come intestazione prima del corpo. La lunghezza può essere codificata a 7 bit o utilizzare un numero intero a dimensione fissa, a seconda dei casi. Se tutti i tuoi elenchi hanno le stesse dimensioni, non hai bisogno di una lunghezza per loro.

Come faccio a farlo da solo:

  • il numero di elenchi (lunghezza come descritto sopra)
  • ogni lista (dimensione fissa di 4 numeri interi)
  • ogni elemento nella lista 7 bit codificati - questa è una codifica a dimensione variabile
  • non è necessario alcun separatore

Dopo lo streaming su un flusso di memoria, prenderei quindi i byte risultanti e userei LZ4 o il tuo algoritmo di compressione preferito. Quindi codifica utilizzando il set di caratteri.

Nota : al momento in cui ho scritto la risposta sopra, ho pensato che gli array sarebbero stati combinati prima della compressione. Risulta che ciascuno deve essere compresso separatamente. Questo è un argomento più difficile e richiede più informazioni sull'origine e sull'utilizzo degli array. Puoi trovare alcune informazioni qui: link

    
risposta data 09.06.2016 - 18:59
fonte

Leggi altre domande sui tag