简体   繁体   中英

In F#, how to correctly use ResizeArray() and an accumulator in an Array.map to change the property of a record

(Newbie question). Simple question.

In C#, I have the following code:

double openspace = (WorkArea.Width - totalcolumnwidth) / (ColumnCount - 1);

double left = WorkArea.Left;

for (int k = 0; k < ColumnCount; k++)
{
    Cursor cursor = new Cursor
                        {
                            TopLeft = new Point(left, WorkArea.Top),
                        };
    cursors.Add(cursor);
    left += Columns[k] + openspace;
}

In F#, I've tried this for simplicity but it fails.

type Cursor = { TopLeft: float }

let columnCount = 5.0   // // columnCount number of cursors in List<Cursor> 

let cursors = new ResizeArray<Cursor>(columnCount)   

let mutable left = 20.0

cursors |> Array.map ( fun k -> left <- left + 10 + k.TopLeft ; {k with TopLeft = left} )

The goal here is to calculate a new TopLeft value for each Cursor in the cursors array based on an accumalator in 'left' and return a new cursors array with each cursor record having its new value.

How is this done correctly? Can it be done without using a mutable "left" variable?

Thank you in advance.

#Addendum: The "columns" is defined as an array of integers (each integer representing the width of a column).

 columns = [|210; 330|]

I don't think you need a fold (or, to be more precise, a scan ) to handle this, because the current TopLeft value can actually be computed without reference to the previous TopLeft value. This is a good case for an array comprehension. Something like this:

    let cursors =
        [|
            for i = 0 to columnCount-1 do
                yield { TopLeft = initialOffset + (columnOffset * float i) }
        |]

This works because the columns are constant-width. For variable-width columns, you would definitely need a scan, like this:

let columnWidths = [| 210; 340; 200; 300 |]
let initialOffset = 100   // left coord of first column
let columnOffset = 20     // gap between columns
let columnLefts =
    (initialOffset, columnWidths)
        ||> Seq.scan (fun acc width ->
            acc + width + columnOffset)
        |> Seq.take columnWidths.Length   // ignore final value
        |> Seq.toArray
printfn "%A" columnLefts

The output is: 100,330,690,910

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