unity toint32 long float convertir convert c# algorithm math compression logic

toint32 - string to int c# unity



Comprimir un número grande(o cadena) a un valor pequeño (6)

Mi página ASP.NET tiene el siguiente parámetro de cadena de consulta:

…?IDs=1000000012,1000000021,1000000013,1000000022&...

Aquí el parámetro IDs siempre tendrá números separados por algo, en este caso,. Actualmente hay 4 números, pero normalmente estarían entre 3 y 7 .

Ahora, estoy buscando un método para convertir cada gran número de arriba en el valor más pequeño posible; comprimir específicamente el valor del parámetro de cadena de consulta de IDs . Ambos, la compresión de cada algoritmo de número o la compresión de todo el valor del parámetro de cadena de consulta IDs son bienvenidos.

  1. Codificar o decodificar no es un problema; simplemente comprimiendo el parámetro de cadena de consulta IDs valor.
  2. Crear un pequeño valor único para IDs y luego recuperar su valor de alguna fuente de datos está fuera del alcance.

¿Hay un algoritmo para comprimir tales números grandes a valores pequeños o para comprimir el valor del parámetro cadena de consulta IDs juntos?


¿Cuál es el rango de tus números? Suponiendo que puedan caber en un entero de 16 bits, yo:

  • Almacene todos sus números como enteros de 16 bits (2 bytes por número, rango -32,768 a 32,767)
  • Cree una copia de seguridad de enteros de 16 bits ( XDR podría ser una buena opción aquí, al menos, asegúrese de manejar la endianidad correctamente)
  • Base64 codifica el bytestream, utilizando la codificación base64 modificada para URL (la red es de aproximadamente 3 caracteres por número)

Como una ventaja adicional, ya no necesitas los caracteres de coma porque sabes que cada número tiene 2 bytes.

Alternativamente, si eso no es lo suficientemente bueno, usaría zlib para comprimir la secuencia de enteros y luego base64 la secuencia comprimida de zlib. También puede cambiar a enteros de 32 bits si el rango de 16 bits no es lo suficientemente grande (es decir, si realmente necesita números en el rango de 1,000,000,000).

Editar:

Tal vez sea demasiado tarde, pero aquí hay una implementación que podría hacer lo que necesita:

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Scratch { class Program { static void Main(string[] args) { //var ids = new[] { 1000000012, 1000000021, 1000000013, 1000000022 }; var rand = new Random(); var ids = new int[rand.Next(20)]; for(var i = 0; i < ids.Length; i++) { ids[i] = rand.Next(); } WriteIds(ids); var s = IdsToString(ids); Console.WriteLine("/nResult string is: {0}", s); var newIds = StringToIds(s); WriteIds(newIds); Console.ReadLine(); } public static void WriteIds(ICollection<Int32> ids) { Console.Write("/nIDs: "); bool comma = false; foreach(var id in ids) { if(comma) { Console.Write(","); } else { comma = true; } Console.Write(id); } Console.WriteLine(); } public static string IdsToString(ICollection<Int32> ids) { var allbytes = new List<byte>(); foreach(var id in ids) { var bytes = BitConverter.GetBytes(id); allbytes.AddRange(bytes); } var str = Convert.ToBase64String(allbytes.ToArray(), Base64FormattingOptions.None); return str.Replace(''+'', ''-'').Replace(''/'', ''_'').Replace(''='', ''.''); } public static ICollection<Int32> StringToIds(string idstring) { var result = new List<Int32>(); var str = idstring.Replace(''-'', ''+'').Replace(''_'', ''/'').Replace(''.'', ''=''); var bytes = Convert.FromBase64String(str); for(var i = 0; i < bytes.Length; i += 4) { var id = BitConverter.ToInt32(bytes, i); result.Add(id); } return result; } } }


Si el único problema es la longitud de la URL, puede convertir números en caracteres base64 y luego convertirlos a números en el servidor


¿Qué patrones tienen los ID que está recibiendo? si dígito a dígito, los ID son aleatorios, entonces el método que voy a proponer no será muy eficiente. pero si los ID que proporcionó como ejemplo son representativos de los tipos que obtendría, entonces ¿podría funcionar lo siguiente?

Motivo esta idea con el ejemplo.

tiene, por ejemplo, 1000000012 como ID que le gustaría comprimir. ¿Por qué no almacenarlo como [{1}, {0,7}, {12}]? Esto significaría que el primer dígito es un 1 seguido de 7 ceros seguido por un 12. Así que si usamos la notación {x} que representaría una instancia de x, mientras que si usamos {x, y} eso significaría que x ocurre y veces en una fila.

podría ampliar esto con un poco de coincidencia de patrón y / o ajuste de función.

por ejemplo, coincidencia de patrones: 1000100032 sería [{1000,2} {32}].

por ejemplo, ajuste de funciones: si sus ID son de 10 dígitos, divida la ID en dos números de 5 dígitos y almacene la ecuación de la línea que atraviesa ambos puntos. si ID = 1000000012, tiene y1 = 10000 y y2 = 12. por lo tanto, su pendiente es -9988 y su intersección es 10000 (suponiendo x1 = 0, x2 = 1). En este caso, no es una mejora, pero si los números fueran más aleatorios, podría ser. Equivalentemente, puede almacenar la secuencia de ID con funciones lineales por partes.

en cualquier caso, esto depende principalmente de la estructura de sus ID.


Aquí hay otro esquema realmente simple que debería dar una buena compresión para un conjunto de números de la forma N + delta donde N es una constante grande.

public int[] compress(int[] input) { int[] res = input.clone(); Arrays.sort(res); for (int i = 1; i < res.length; i++) { res[i] = res[i] - res[i - 1]; } return res; }

Esto debería reducir el conjunto {1000000012,1000000021,1000000013,1000000022} a la lista [1000000012,1,9,1] , que luego puede comprimir aún más representando los números en la codificación base47 como se describe en otra respuesta.

Usando codificación decimal simple, esto va de 44 caracteres a 16 caracteres; es decir, 63%. (Y usar base47 dará incluso más compresión).

Si no es aceptable ordenar los identificadores, no obtendrá una compresión tan buena. Para este ejemplo, {1000000012,1000000021,1000000013,1000000022} comprime en la lista [1000000012,9,-8,9] . Eso es solo un caracter mas largo para este ejemplo

De cualquier manera, esto es mejor que un algoritmo de compresión genérico o esquemas de codificación ... PARA ESTE TIPO DE ENTRADA.


Supongo que está haciendo esto como una solución para solicitar restricciones de longitud de URL ...

Otras respuestas han sugerido codificar los números de identificación decimal en hexadecimal, base47 o base64, pero puede (en teoría) hacer mucho mejor que eso mediante el uso de LZW (o similar) para comprimir la lista de identificación. Según la cantidad de redundancia que haya en sus listas de ID, podría obtener una reducción de más del 40%, incluso después de volver a codificar los bytes comprimidos como texto.

En pocas palabras, sugiero que encuentres una biblioteca de compresión de texto lista para usar implementada en Javascript y la uses para comprimir la lista de ID. Luego codifique la cadena de bytes comprimida utilizando base47 / base64, y pase la cadena codificada como el parámetro URL. En el lado del servidor, haga lo contrario; es decir, decodificar seguido de descompresión.

EDITAR: Como experimento, creé una lista de 36 identificadores diferentes como los que suministró y compré utilizando gzip. El archivo original tiene 396 bytes, el archivo comprimido tiene 101 bytes y el archivo comprimido + base64 138 bytes. Eso es una reducción del 65% en general. Y la relación de compresión podría mejorar para archivos más grandes. Sin embargo, cuando probé esto con un pequeño conjunto de entrada (por ejemplo, solo los 4 identificadores originales), no obtuve compresión, y después de la codificación el tamaño fue mayor que el original.

Google "lzw library javascript"

En teoría, podría haber una solución más simple. Envíe los parámetros como "datos de publicación" en lugar de en la URL de solicitud, y obtenga que el navegador aplique la compresión usando una de las codificaciones que entiende. Eso le dará más ahorros también, ya que no es necesario codificar los datos comprimidos en caracteres de URL legales.

El problema es hacer que el navegador comprima la solicitud ... y hacerlo de una manera independiente del navegador.


Básicamente, necesitas mucho espacio para tus números porque estás usando la base 10 para representarlos. Una mejora sería usar base 16 (hex). Entonces, por ejemplo, puede representar 255 (3 dígitos) como ff (2 dígitos).

Puede llevar ese concepto aún más lejos utilizando una base numérica mucho más grande ... el conjunto de todos los caracteres que son parámetros de cadena de consulta válidos:

AZ, az, 0-9, ''.'', ''-'', ''~'', ''_'', ''+''

Eso le da una base de 67 caracteres para trabajar (vea Wikipedia en QueryString ).

Eche un vistazo a esta publicación SO para los enfoques para convertir la base 10 en bases de números arbitrarios.

EDITAR:

En la publicación SO vinculada, mira esta parte:

string xx = IntToString(42, new char[] { ''0'',''1'',''2'',''3'',''4'',''5'',''6'',''7'',''8'',''9'', ''A'',''B'',''C'',''D'',''E'',''F'',''G'',''H'',''I'',''J'',''K'',''L'',''M'',''N'',''O'',''P'',''Q'',''R'',''S'',''T'',''U'',''V'',''W'',''X'',''Y'',''Z'', ''a'',''b'',''c'',''d'',''e'',''f'',''g'',''h'',''i'',''j'',''k'',''l'',''m'',''n'',''o'',''p'',''q'',''r'',''s'',''t'',''u'',''v'',''w'',''x''});

Eso es casi lo que necesitas. Simplemente amplíelo agregando los pocos caracteres que falta:

yz.- ~ _ +

A esa publicación le falta un método para volver a la base 10. No voy a escribirla :-) pero el procedimiento es el siguiente:

Defina un contador al que llamaré TOTAL.

Mira el personaje que está más a la derecha y encuentra su posición en la matriz.
TOTAL = (la posición del carácter en la matriz) Ejemplo: La entrada es BA1. TOTAL es ahora 1 (dado que "1" está en la posición 1 en la matriz)

Ahora mira el siguiente carácter a la izquierda del primero y encuentra su posición en el conjunto. TOTAL + = 47 * (la posición del carácter en la matriz) Ejemplo: La entrada es BA1. TOTAL es ahora (47 * 11) + 1 = 518

Ahora mira el siguiente carácter a la izquierda del anterior y encuentra su posición en la matriz. TOTAL + = 47 * 47 * (la posición del carácter en la matriz) Ejemplo: La entrada es BA1. El total es ahora (47 * 47 * 10) + (47 * 11) + 1 = 243508

Y así.

Le sugiero que escriba una prueba unitaria que convierta un grupo de números base 10 en la base 47 y luego otra vez para asegurarse de que su código de conversión funcione correctamente.

Observe cómo representó un número de base 10 de 6 dígitos en solo 3 dígitos de la base 47 :-)