简体   繁体   中英

F# - Array - Subtract N-1 Element

I am trying to subtract an n-1 element as part of a calculation using a constant and two arrays as follows:

module SOQN =

   open System

   let firstArray  = [|0.02;0.03;0.05;0.07;0.11|]
   let secondArray = [|0.30;0.50;0.70;1.10;1.30|]
   let constant    = 0.37

   let minusOneElement = 0.00
   let result = Array.map2 (fun x y -> (x - (constant * (y - minusOneElement)))) firstArray secondArray

   printfn "Result: %A" result

   (*
      Expected Result: [|-0.091;-0.044;-0.024;0;0|]
      Actual Result:   [|-0.091;-0.155;-0.209;-0.337;-0.371|]
   *)

As you can see, the first output value is correct but the rest are not given that I do not know how to construct "minusOneElement", which should be successive elements of "secondArray" - namely, 0.30 0.50 0.70 and 1.10. There is an additional restriction that the current element of "secondArray" be less than one; otherwise, the corresponding result value is set equal to zero.

If I interpret your requirements correctly, you wish to take the second array and generate pairs (current element, previous element), where the previous element is set to 0.0 for the first current element.

You can use Seq.windowed to generate the pairs (after prepending a singleton array of 0.0 for the first previous element):

let fst  = [|0.02;0.03;0.05;0.07;0.11|]
let snd = [|0.30;0.50;0.70;1.10;1.30|]
let snd' = Seq.windowed 2 (Array.append [|0.0|] snd) |> Seq.toArray
let constant = 0.37

Revising your map operation:

let result = Array.map2 (fun x (y: float []) -> (if y.[1] < 1.00 then (x - (constant * (y.[1] - y.[0]))) else 0.00)) fst snd'

Which yields your expected result (note the snd' pairs for reference):

val snd' : float [] [] =
    [|[|0.0; 0.3|]; [|0.3; 0.5|]; [|0.5; 0.7|]; [|0.7; 1.1|]; [|1.1; 1.3|]|]

val result : float [] = [|-0.091; -0.044; -0.024; 0.0; 0.0|]

The following snippet appears to work:

module SOANS =

   open System

   let firstArray  = [|0.02;0.03;0.05;0.07;0.11|]
   let secondArray = [|0.30;0.50;0.70;1.10;1.30|]
   let lenSecondArray = secondArray.Length
   let thirdArray = Array.permute (fun index -> (index + (1)) % lenSecondArray) secondArray
   thirdArray.[0] <- 0.00
   let constant    = 0.37

   let result = Array.map3 (fun x y z -> (if y < 1.00 then (x - (constant * (y - z))) else 0.00)) firstArray secondArray thirdArray

   printfn "Result: %A" result

   (*
      Expected Result: [|-0.091;-0.044;-0.024;0;0|]
      Actual Result:   [|-0.091;-0.044;-0.024;0;0|]
   *)

I would appreciate a more idiomatic solution, if possible.

For each y.[n] , construct a tuple of it and of its difference to y.[n-1] . A functional way to this end is a scan operation, which populates the collection with the intermediate results of a fold . In contrast to Seq.windowed (or for that matter, Seq.pairwise ), the length of the resulting collection is not less than the source. It contains one extra element, the initial state is prepended.

let first = [|0.02;0.03;0.05;0.07;0.11|]
let second = [|0.30;0.50;0.70;1.10;1.30|]

let diff2 = Array.scan (fun (prv, _) cur -> cur, cur - prv) (0., 0.) second

(first, diff2.[1..])
||> Array.map2 (fun x (y, dy) ->
    if y < 1. then x - 0.37 * dy else 0. )
// val it : float [] = [|-0.091; -0.044; -0.024; 0.0; 0.0|]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM