将许多数字存储为一个唯一的数字
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 为基数更容易使用。
我需要将许多号码(我可以决定哪些号码)存储为一个唯一号码,我应该能够从中检索原始号码。
我已经知道 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 为基数更容易使用。