I'm attempting a few minor tasks in F# to help get a handle on the language.
I would like to write a function that takes a n-dimensional list and returns a 1-dimensional list containing all the elements from each dimension.
For example, if the input was the following 3-dimensional list: [[[1;2];[3;4]];[[5;6];[7;8]]], the output would be: [1;2;3;4;5;6;7;8]
For 2-dimensions -> 1-dimension the function is pretty straightforward:
let coalesce list= List.collect(fun item -> item) list
Here is my attempt to generalize this to n-dimensions:
let rec coalesce (list, dimension) =
if dimension = 1 then list
else coalesce (List.collect(fun item -> item) list, dimension - 1)
I get the following error when I try to compile:
error FS0001: Type mismatch. Expecting a
'a list list
but given a
'a list
The resulting type would be infinite when unifying ''a' and ''a list'
The issue is here:
List.collect(fun item -> item) list
There's obviously something wrong with my thinking. What's the proper way to write this sort of function?
This operation is not well-typed, but here's a sample that works on IEnumerables and returns a list<obj>:
let rec coalesce(list:System.Collections.IEnumerable, dim) =
[
if dim=1 then for x in list do yield x
else
for x in list do
match x with
| :? System.Collections.IEnumerable as s ->
yield! coalesce(s, dim-1)
| _ -> failwith "bad shape"
]
printfn "%A" (coalesce([1;2], 1))
printfn "%A" (coalesce([[1;2];[3;4]], 2))
printfn "%A" (coalesce([[[1;2];[3;4]];[[5;6];[7]]], 3))
You can also write
let rec flatten(list:System.Collections.IEnumerable) =
[for x in list do
match x with
| :? System.Collections.IEnumerable as s -> yield! flatten(s)
| _ -> yield x
]
which is more general, e.g.
let weird : obj list = [[box [1;2]; box 3]; 4; [box [5;6]; box 7]]
printfn "%A" (flatten weird)
EDIT
@Jon Harrop suggested another strategy - create a new type for nested lists:
type NestedListElement<'T> = //'
| L of NestedListElement<'T> list //'
| V of 'T //'
let rec flatten nlist =
[for x in nlist do
match x with
| L l -> yield! flatten l
| V v -> yield v
]
let nested = [L[L[V 1;V 2]; V 3]; V 4; L[L[V 5;V 6]; V 7]]
printfn "%A" (flatten nested)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With