我有一个函数,我想将一个浮点数列表转换为另一个浮点数,其中对于每个元素,我希望将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]
为此,我将每个元素的一半添加到下一个元素中。
现在我想出了这个,但只适用于大小为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#还很新鲜,还有很多我还不知道的事情。猜测这里的一般情况是:如何将不同的函数映射到列表的第一个和最后一个元素,将一个函数映射到其他元素?
提前致谢,
格特 - 扬
答案 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
|(_,[]) -> []