将许多数字存储为一个唯一的数字

Store many numbers as a single unique number

我需要将许多号码(我可以决定哪些号码)存储为一个唯一号码,我应该能够从中检索原始号码。
我已经知道 2 种方法:

1) 算术基本定理(素数)
假设我有 5 个值,我为每个值分配了一个非 1 的素数

a = 2
b = 3
c = 5
d = 7
e = 13

如果我想存储 a、b 和 c,我可以将它们相乘 2*3*5=30 而且我知道没有其他素数乘积可以是 30。然后检查一个值是否包含,例如 b,所有 i需要做的是30 % b == 0

2) 位掩码 就像 Linux 权限一样,使用 2 的幂并对每个值求和

但是这两种方法发展得很快(第一种方式比第二种方式快),而且使用素数需要我有很多素数。
例如,当您有上千个值时,是否有任何其他方法可以有效地执行此操作?

Is there any other method to do this efficiently when you have, for example, a thousand values?

我不是数学家,但这是基础数学,一切都取决于范围

范围 0-1: 你想存储 4 个数字 0-1 - 它基本上是二进制系统

Number1 + Number2 * 2^1 + Number3 * 2^2 + Number4 * 2^3

范围0-50你要存储4个数字0-49

Number1 + Number2 * 50^1 + Number3 * 50^2 + Number4 * 50^3

范围0-X你要存储N个数0-X

Number1 + Number2 * (X+1)^1 + Number3 * (X+1)^2 + ... + NumberN * (X+1)^(N-1)

如果你的数字没有模式(所以它可以以某种方式被压缩)那么真的没有其他方法。

与素数不同,计算机也非常容易解析数字


预设值

@FlorainK 的评论指出了我错过的事实

(i can decide which numbers)

唯一合乎逻辑的解决方案是提供您的号码参考

0 is 15342
1 is 6547
2 is 76234
3 is "i like stack overflow"
4 is 42141

所以您将工作范围 0-4(5 个选项)和任何组合长度。当"encoding"和"decoding"数字

时使用参考

a thousand values?

因此您将使用范围 0-999

0 is 62342
1 is 7456345653
2 is 45656234532
...
998 is 7623452
999 is 4324234326453

假设您使用 64 位系统和使用 64 位整数的programming/db语言

2^64 = 18446744073709551616

您的最大范围是 1000^X < 18446744073709551616,其中 X 是您可以存储在一个 64 位整数中的数字数量

也就是6.

您只能存储 6 个单独的数字 0-999,这将适合一个 64 位整数。

0,0,0,0,0,0 is 0
1,0,0,0,0,0 is 1
0,1,0,0,0,0 is 1000
999,999,999,999,999,999 is ~1e+18

好的,所以你想存储 "a,b,c" 或 "a,b" 或 "a,b,c,d" 或 "a" 等(感谢@FlorianK)

在这种情况下可以使用按位运算符和二的幂

$a = 1 << 0; // 1
$b = 1 << 1; // 2
$c = 1 << 2; // 4
$d = 1 << 3; // 8
.. etc

假设 $flag$a$c

$flag = $a | $c; // $flag is integer here

现在检查一下

$ok = ($flag & $a) && ($flag & $c); // true
$ok = ($flag & $a) && ($flag & $b); // false

所以在 64 位 system/language/os 中你最多可以使用 64 个标志,这给你一个 2^64 组合

别无选择。素数的情况更糟,因为您会跳过中间的许多数字,而二进制系统会使用每个数字。


我看到你正在使用数据库,你想把它存储在数据库中。

我真的认为我们正在处理这里 XY Problem,您应该重新考虑您的申请,而不是做出这样的变通办法。

如果您要存储以 10 为基数的数字,则可以通过以 11 为基数的数字进行转换。随着基础的增加,你有一个额外的'digit'。使用该数字作为分隔符。因此,三个以 10 为基数的数字“10、42、457”变为“10A42A457”:一个以 11 为基数的数字(附加数字为 'A')。

无论您的原始数字是什么基数,将基数增加 1 并连接,使用额外的数字作为分隔符。这将在增加的基数中为您提供一个数字。

单个数字可以存储在您认为方便的任何数字基数中:例如二进制、二进制或十六进制。

要检索您的原始数字,只需将其转换为 11 进制(或其他)并将多余的数字替换为分隔符。

预计到达时间:您不必使用 11 进制。单个数字“10A42A457”也是有效的十六进制数,因此可以使用任何 11 或以上的进制。十六进制可能比以 11 为基数更容易使用。