我有一个函数接收一个整数并返回该数字的二进制列表:
let DecimalToBase2 (n:int) =
Convert.ToString(n,2)
|> Seq.map (fun c -> int c - int '0')
|> Seq.toList
DToB 23 -> [1; 0; 1; 1; 1]
DToB 511 -> [1; 1; 1; 1; 1; 1; 1; 1; 1]
DToB 512 -> [1; 0; 0; 0; 0; 0; 0; 0; 0; 0]
我总是期待一个长度为10的列表,我需要将“0”附加到列表的开头。
我知道F#列表是不可变的,但我不知道我使用的代码是否是最好的方法。
'收益'如何运作?
是创建多个列表并在运行时附加它们还是仅添加一个?
let DecToBase2 n =
let xx = DecimalToBase2 n
let result =
[
for i in xx.Length .. 9 do
yield 0
done
] @ xx
result
D 23 -> [0; 0; 0; 0; 0; 1; 0; 1; 1; 1]
D 511 -> [0; 1; 1; 1; 1; 1; 1; 1; 1; 1]
D 512 -> [1; 0; 0; 0; 0; 0; 0; 0; 0; 0]
答案 0 :(得分:2)
这是一种稍微更具功能性的方法。它可能不是最短的方式,但是当你试图在功能上思考时,这不应该是你想要的。我们要做的是使用一个函数计算位,然后使用另一个函数将结果填充到所需的长度。两者都将以递归方式执行此操作。 loop
将数字的最低幅度位附加到列表中,然后除以2并重复直到没有剩余位。然后pad
会在0到12之前,直到列表达到所需的大小(10):
let d2b n =
let rec loop n lst =
if n > 0 then loop (n >>> 1) ((n &&& 1) :: lst) else lst
let rec pad lst size filler =
if (List.length lst < size) then pad (filler :: lst) size filler else lst
pad (loop n []) 10 0
您的尝试正在使用所谓的列表理解,这是一种公平的方式。 @
通常被认为是代码气味,因为它有时用于将单个项目添加到列表的末尾,其中其性能非常差(它是O(N),其中N是列表的长度)剩下)。但是,在这种情况下,我不认为它比我上面的更糟糕。
有几种较短的方法可以做到这一点,不确定它们是否有更好的性能。您可以使用列表推导来测试每个位:
let d2b n = [for i = 9 downto 0 do yield (n >>> i) &&& 1]
或使用单个帮助函数来测试长度(评论中的honco建议)
let d2b n =
let rec loop n lst =
if List.length lst < 10 then loop (n >>> 1) ((n &&& 1) :: lst) else lst
loop n []