开发者

Returning different types of arrays from a lambda expression in F#

i have a List of records

type Item = { Color : string; Size : int}
let itemList = [{Color="Red"; Size=1};
                {Color="Green"; Size=2};
                {Color="Blue"; Size=3};]

I am looking to get turn my list of records into an array of values like [|"Red";"Green";"Blue"|] or [|1;2;3|]

I can sorta get there like this

type ItemType =
| Color of string
| Size of int

type ItemEnum =
| C
| S

let GetProp x y =
match x with
| C -> List.toArray y |> Array.map(fun x -> ItemType.Color(x.Color))
| S -> List.toArray y |> Array.map(fun x -> ItemType.Size(x.Size))

but when I call GetProp S itemList I get back [|Size 1; Size 2; Size 3|]. Useful but not exactly what I'm looking for.

I've tried the following

let GetProp2 x y : 'a[] =
match x with
| Color -> List.toArray y |> Array.map(fun x -> x.Color)
| Size -> List.toArray y |> Array.map(fun x -> x.Size)

but it doesn't like the two different return types.

I'm 开发者_运维技巧open to suggestions on different (more functional?) ways of doing this and would appreciate your input.


A custom variant type is indeed the way to go here (and generally wherever you need a type that is "either X or Y"). However, as defined, your function looks like it might return an array in which Color and Size are mixed, but in practice it seems that you only want it to return one or the other. If so, this is best reflected in the types:

type Items =
| Colors of string[]
| Sizes of int[]

let GetProp x ys =
match x with
| C -> Colors [| for y in ys -> y.Color |]
| S -> Sizes [| for y in ys -> y.Size |]

By the way, is there any particular reason why you use array for return type here, rather than the usual lazy sequence (seq)?


You can use active patterns to see your data form few points of view:

let (|AsColor|) (v: Item list) = [| for i in v -> i.Color |];;

let (|AsSize|) (v: Item list) = [| for i in v -> i.Size |];;

match itemList,itemList with
  |AsColor ca, AsSize sa -> printfn "%A; %A" ca sa;;


Go go gadget Array Comprehensions!

> [| for a in itemList do yield a.Size |];;
val it : int [] = [|1; 2; 3|]
> [| for a in itemList do yield a.Color |];;
val it : string [] = [|"Red"; "Green"; "Blue"|]

You don't need an intermediate ItemType or ItemEnum data structure.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜