我正在为 F# 开发 Akka。我想按顺序生成字母数字字符串。
例如:第一个字符串是 0,第二个是 1,然后是 2,等等。当它达到 9 时,我想让它变成小写的“a”。当它到达“z”时,我希望它变成大写的“A”。当它到达“Z”时,它应该变成 00。等等......
我想按顺序搜索这些字符串的整个空间,我不想随机生成它们。基本上,我要求增加函数,例如i++
,但不是以 10 为基数的算术,我希望它具有以 62 为基数的算术。在像 F# 这样的函数式语言中,最好的方法是什么?我可以以某种方式利用字母的 ASCII 表示是有序的这一事实吗?但随后数字与 ASCII 中的字母表示相邻。
额外问题:我怎样才能在这个系统上执行任何算术,让我们说x <- x+100
?
您基本上需要的只是一种将数字转换为字符串表示形式的方法,反之亦然。顺便说一下,这个任务对于每个基地都是一样的。这里有一个分步解决方案。
要将数字转换为二进制,您可以使用以下算法。
let rec toBinary x =
if x = 0 then "0"
else
let y = x % 2
(toBinary ((x-y)/2)) + (string y)
例如,这就是您转换为八进制表示的方式。
let rec toOctal x =
if x = 0 then "0"
else
let y = x % 8
(toOctal ((x-y)/8)) + (string y)
如你所见,它总是一样的。在底座上制作一个模块,以获得最正确的数字。重复基数的减法和除法。
20
20 % 2 = 0 // 20 / 2
10 % 2 = 0 // 10 / 2
5 % 2 = 1 // (5-1) / 2
2 % 2 = 0 // 2 / 1
1 % 2 = 1 // (1-1) / 2
0
这样,您可以从右到左使用数字,它适用于任何基数。
现在,您可以通过将基数作为数字来使其更通用,而不是编写每个版本。
let rec toBase nbase x =
if x = 0 then "0"
else
let y = x % nbase
(toBase nbase ((x-y)/nbase)) + (string y)
为了使其更加通用,您可以提供一个字符串列表,以及您的映射。像这样。
let rec toBase' nbase x =
let bse = List.length nbase
if x = 0 then
nbase.[0]
else
let y = x % bse
(toBase' nbase ((x-y)/bse)) + (nbase.[y])
现在,您可以创建任意映射。
let toBin = toBase' ["0";"1"]
let toABCD = toBase' ["A";"B";"C";"D"]
let toHex = toBase' ["0";"1";"2";"3";"4";"5";"6";"7";"8";"9";"A";"B";"C";"D";"E";"F"]
let toOct = toBase' ["0";"1";"2";"3";"4";"5";"6";"7"]
接下来,你应该做相反的事情。映射一个字符串,返回一个数字。通常的方法是理解,一个数字是一个位置的乘法。例如,二进制数“1010”的真正含义是:
(1 * 8) + (0 * 4) + (1 * 2) + (0 * 1)
作为代码:
let rec toInt nbase x =
let bse = List.length nbase
let mut = pown bse (String.length x - 1)
if x = "" then
0
else
let fc = string (x.[0])
let index = List.findIndex (fun e -> e = fc) nbase
(toInt nbase (x.[1..])) + (index * mut)
现在您可以定义反向。
let toBin = toBase' ["0";"1"]
let fromBin = toInt ["0";"1"]
let toABCD = toBase' ["A";"B";"C";"D"]
let fromABCD = toInt ["A";"B";"C";"D"]
let toHex = toBase' ["0";"1";"2";"3";"4";"5";"6";"7";"8";"9";"A";"B";"C";"D";"E";"F"]
let fromHex = toInt ["0";"1";"2";"3";"4";"5";"6";"7";"8";"9";"A";"B";"C";"D";"E";"F"]
let toOct = toBase' ["0";"1";"2";"3";"4";"5";"6";"7"]
let fromOct = toInt ["0";"1";"2";"3";"4";"5";"6";"7"]
如果你现在想要一个数字流,你可以 List.map 你的数字,或者从中创建一个序列。例如,二进制数流。这个序列就是你想要的“++”操作。一个计算所有变体的懒惰序列。
let binaryStream = Seq.initInfinite toBin
for x in Seq.take 10 binaryStream do
printfn "%s" x
// Will print
// 0
// 01
// 010
// 011
// 0100
// 0101
// 0110
// 0111
// 01000
// 01001
将打印第一个,10 个二进制数。如果要将 + 100 添加到字符串,请先将其转换为数字,再转换为数字乘法,然后再将其转换回字符串。或提供您想要的那些功能。例如添加两个二进制字符串。
let addBin x y =
toBin ((fromBin x) + (fromBin y))
addBin "1000" "1010" // 8 + 10
现在你可以做你的base62了。例如,打印前 200 个字符串。
let toB62 =
toBase' (
List.map string [0..9]
@ List.map string ['a' .. 'z']
@ List.map string ['A' .. 'Z'])
let fromB62 =
toInt (
List.map string [0..9]
@ List.map string ['a' .. 'z']
@ List.map string ['A' .. 'Z'])
let b62stream = Seq.initInfinite toB62
for x in Seq.take 200 b62stream do
printfn "%s" x
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句