简体   繁体   中英

What is the best way of creating a repeating sequence in an array in F#?

In Python you can create the array and just add * n to make it repeat itself a number of times. But I want to know what is the best way to do this in F# without having to use a long loop. Also is it better to use an array, list or sequence for this? I'm looking for something like below.

let array = [| 2; 3; 4; 5; 6; 7; 8; 9; 10; 10; 10; 10; 1 |] * 4 // for every suit

Lastly is it possible to do something such as 2 .. 10; 10; 10; 10; 1? Thanks.

Use Array.replicate :

[| 1; 2; 3 |] |> Array.replicate 4 |> Array.concat

// [|1; 2; 3; 1; 2; 3; 1; 2; 3; 1; 2; 3|]

Or Array.create :

[| 1; 2; 3 |] |> Array.create 4 |> Array.concat

// [|1; 2; 3; 1; 2; 3; 1; 2; 3; 1; 2; 3|]

You can define your own version of that python feature pretty easily:

let duplicate times sequence =
    seq {
        for i = 1 to times do yield! sequence
    }

This works for sequences, but you can apply it to lists or arrays using the built-in conversion functions:

[0; 1; 2; 3; 4; 5] |> duplicate 4 |> Seq.toList

You could even define a custom operator to work with arrays specifically:

let ( ** ) sequence times = duplicate times sequence |> Seq.toArray

Then you would be very near the python syntax:

[| 1; 2; 3 |] ** 4

Returns:

val it : int [] = [|1; 2; 3; 1; 2; 3; 1; 2; 3; 1; 2; 3|]

EDIT

Using the built-in Array.replicate that TheQuickBrownFox mentioned in their answer, you can define the custom operator with just the following line:

let ( ** ) sequence times = Array.replicate times sequence |> Array.concat

Nobody has yet answered the last part of your question (about whether you can do something like 2 .. 10; 10; 10; 10; 1 ), so I'll tackle that one.

The .. syntax in F# cannot be used in the same expression as a semicolon; if you try this:

let values = [| 2 .. 10; 10; 10; 10; 1 |]

Then you'll get this error:

error FS0010: Unexpected symbol ';' in binding. Expected '|]' or other token

However, it's pretty easy to work around this with Array.append :

let values = Array.append [| 2 .. 10 |] [| 10; 10; 10; 1 |]

This works, and produces the array [|2; 3; 4; 5; 6; 7; 8; 9; 10; 10; 10; 10; 1|] [|2; 3; 4; 5; 6; 7; 8; 9; 10; 10; 10; 10; 1|] [|2; 3; 4; 5; 6; 7; 8; 9; 10; 10; 10; 10; 1|] that you're looking for.

Two things to remember when using Array.append : first, it's an O(N) operation. That doesn't matter when dealing with small arrays like this one, but if you have to append two very large arrays with thousands of items, keep that in mind. Second, the order of the parameters matters: Array.append ab returns a different result than Array.append ba . This might seem obvious, but when you start using the |> operator, things get less obvious. If you do a |> Array.append b , that's the same as writing Array.append ba . This will catch you by surprise from time to time. So just keep in mind that when you use the |> operator, the item before |> is going to go at the end of the parameter list. To avoid surprise, it's probably best to just avoid the use of |> when you're dealing with Array.append (or List.append or Seq.append ) and always write the equivalent of Array.append ab .

One more note: the List.append function has an operator equivalent: @ is the operator that appends two lists. It does not work for arrays, though:

[1; 2] @ [3; 4]  // Works, produces [1; 2; 3; 4]
[|1; 2|] @ [|3; 4|]  // Type error: expected list, found array

If you're using lists, you can write [ 2.. 10 ] @ [ 10; 10; 10; 1 ] [ 2.. 10 ] @ [ 10; 10; 10; 1 ] [ 2.. 10 ] @ [ 10; 10; 10; 1 ] . With arrays, you have to write Array.append [| 2 .. 10 |] [| 10; 10; 10; 1 |] Array.append [| 2 .. 10 |] [| 10; 10; 10; 1 |] Array.append [| 2 .. 10 |] [| 10; 10; 10; 1 |] .

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