是否有更多功能的方法将n个元素添加到列表的开头?

时间:2014-11-18 04:16:12

标签: f#

我有一个函数接收一个整数并返回该数字的二进制列表:

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]

1 个答案:

答案 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 []