将不同的函数映射到列表中的第一个和最后一个元

时间:2011-10-03 09:53:54

标签: list f#

我有一个函数,我想将一个浮点数列表转换为另一个浮点数,其中对于每个元素,我希望将x%的元素溢出到元素i + 1

示例:

let p3 = [0.1; 0.2; 0.4; 0.2; 0.1]

然后p3_s应该是:

[0.05; 0.15; 0.3; 0.3; 0.2]

为此,我将每个元素的一半添加到下一个元素中。

  • 0.1变为0.05,因为它给下一个0.05,没有先前的元素
  • 0.2变为0.15,因为它给下一个0.1,并且得到0.05 第一次
  • etc
  • 最后0.1变为0.2,因为它来自.01 以前。没有下一个元素。

现在我想出了这个,但只适用于大小为5的列表:

// create list
let p3 = [0.1; 0.2; 0.4; 0.2; 0.1]

let shiftList orgList shift =    

    // chop list up in tuples of what stays and what moves
    let ms = orgList |> List.map (fun p-> (p * shift, p * (1.0-shift))) 

    // map new list 
    ms |> List.mapi (fun i (move, stay) -> 
        match i with 
        | 0 -> stay
        | 4 -> stay + fst ms.[i-1] + move // note hardcoded 4
        | _ -> stay + fst ms.[i-1])

// get shifted list
shiftList p3 0.5

现在提出问题:

1)如何在任何长度列表上匹配?现在我在匹配表达式中对4进行了硬编码,但我希望能够接受任何长度列表。

我试过了:

let shiftList orgList shift =    

    // chop list up in tuples of what stays and what moves
    let ms = orgList |> List.map (fun p-> (p * shift, p * (1.0-shift))) 

    // find length 
    let last = orgList.Length - 1

    // map new list 
    ms |> List.mapi (fun i (move, stay) -> 
        match i with 
        | 0     -> stay
        | last  -> stay + fst ms.[i-1] + move 
        | _     -> stay + fst ms.[i-1]) // now this one will never be matched

但是这不会将last视为数字4,而是变为i的变量,即使上面已经声明了last

那么我怎样才能匹配一个变量,以便我可以区别对待最后一个?找到第一个很容易,因为它是0。

2)你会怎么做?我对F#还很新鲜,还有很多我还不知道的事情。猜测这里的一般情况是:如何将不同的函数映射到列表的第一个和最后一个元素,将一个函数映射到其他元素?

提前致谢,

格特 - 扬

5 个答案:

答案 0 :(得分:5)

这是一个更实用的解决方案

let func (input:float list) =
    let rec middle_end input_ =
        match input_ with
        |h::t::[] -> ((h/2.0)+t)::[]
        |h::t::tt ->((h+t)/2.0)::(middle_end (t::tt))
        | _ -> [] //fix short lists
    let fst = input.Head/2.0
    fst::middle_end(input)

此外,这只需要单次通过列表,而不是Ramon的解决方案中的3,以及较少的临时存储。

答案 1 :(得分:2)

作为编写自己的递归函数的替代方法,您还可以使用内置函数。使用Seq.windowed可以很容易地解决问题。尽管如此,您仍然需要最后一个元素的特殊情况:

let p3 = [0.1; 0.2; 0.4; 0.2; 0.1] 

// Prefix zero before the list, pre-calculate the length
let p3' = (0.0 :: p3)
let l = p3.Length

// Perform the transformation
p3' 
|> Seq.windowed 2
|> Seq.mapi (fun i ar -> 
    (if i = l - 1 then ar.[1] else ar.[1] / 2.0) + ar.[0] / 2.0)
|> List.ofSeq

答案 2 :(得分:1)

你想这样做:

let shiftList orgList shift =    

    // chop list up in tuples of what stays and what moves
    let ms = orgList |> List.map (fun p-> (p * shift, p * (1.0-shift))) 

    // find length 
    let last = orgList.Length - 1

    // map new list 
    ms |> List.mapi (fun i (move, stay) -> 
        match i with 
        | 0     -> stay
        | last' when last' = last -> stay + fst ms.[i-1] + move 
        | _     -> stay + fst ms.[i-1]) // now this one will never be matched

答案 3 :(得分:1)

使用List.scan:

let lst = [0.1; 0.2; 0.4; 0.2; 0.1]
let len = (lst.Length-1)

lst 
|> List.mapi (fun i e -> (i,e)) 
|> List.scan (fun (c,_) (i,e) -> if i = len then (0.0,e+c) else ((e/2.0),(e/2.0)+c)) (0.0,0.0) |> List.tail 
|> List.map snd

答案 4 :(得分:1)

另一个想法,

let bleh p3 =
    match Seq.fold (fun (give,acc) i -> i*0.5,((i*0.5 + give) :: acc)) (0.0,[]) p3 with
    |(give,h::t) -> give+h :: t |> List.rev
    |(_,[]) -> []