I've been struggling with this for a while now. While I had some long imperative method that worked, I decided to redesign this part:
- Take a list of lists
Make a list of the first item of each sublist, then again the first item, but from the last sublist the second item, then the third, until that last list is exhausted, do the same for the N-1 sublist, which basically gives a kind of product of all these lists
In other words:
[abc][FG][98]
should be evaluated like (apply functionf
to each item, comma's are for readability): [aF9,aF8,aG9,aG8,bF9,bF8,bG9,bG8,cF9,cF8,cG9,cG8]Flatten that and apply a function to each item of the result, which itself returns a list
- These lists are then flattened to return a singly linked list
- When a sublist is empty (call this E), then only sublists
0 .. E-1
are evaluated (not in my example)
Here's a working example which clearly shows its recursive nature, but obviously only goes as deep as three lists:
let rec nestedApply f inp =
match inp with
| [] -> []
| [x] -> x |> List.collect f
| [x;y] ->
x
|> List.collect (fun a -> y |> List.collect (fun b -> [a;b]))
|> List.collect f
| [x;y;z] ->
x
|> List.collect (fun a -> y |> List.collect (fun b -> z |> List.collect (fun c -> [a;b;c])))
|> List.collect f
| head::tail ->
// ??? I gave the following several attempts but couldn't get it right
nestedApply f tail
|> List.collect (fun a -> a::head)
|> List.collect f
I'd prefer a solution that doesn't blow up the stack. Eventually I'll need this to lazy-eval, so I probably resort to sequences, but with lists I think the algorithm will be easiest to think about.
Example: nestedApply (fun a -> [a]) [[1 .. 5];[6;7];[11;12]]
Example output:
[1; 6; 11; 1; 6; 12; 1; 7; 11; 1; 7; 12; 2; 6; 11; 2; 6; 12; 2; 7; 11; 2; 7;
12; 3; 6; 11; 3; 6; 12; 3; 7; 11; 3; 7; 12; 4; 6; 11; 4; 6; 12; 4; 7; 11; 4;
7; 12; 5; 6; 11; 5; 6; 12; 5; 7; 11; 5; 7; 12]
As an aside, since this seems like a pretty "normal" algorithm, though it isn't a cartesian product, what is a typical well-known algorithm that this relates closest to?