This comes up fairly often, and I always find myself fighting against it. So I'd like the definitive solution, if there is one.
The essential problem boils down to this conflict:
This is typically solved using chain
(or flat_map
) in functional languages.
To take a concrete example, say you want to list all possible pairs from the list 0 1 2 3
, where the first is strictly less than the second:
0 1
0 2
0 3
1 2
1 3
2 3
Of course, you could table ,/
or catalog {
to get the full cross product, and then filter so you're left with just the upper triangle:
That is take the result of ,"0/~ i.4
:
0 0
0 1
0 2
0 3
1 0
1 1
1 2
1 3
2 0
2 1
2 2
2 3
3 0
3 1
3 2
3 3
Actually, to make the geometry more clear, let's display it as ;/"2 ,"0/~ i.4
:
┌───┬───┬───┬───┐
│0 0│0 1│0 2│0 3│
├───┼───┼───┼───┤
│1 0│1 1│1 2│1 3│
├───┼───┼───┼───┤
│2 0│2 1│2 2│2 3│
├───┼───┼───┼───┤
│3 0│3 1│3 2│3 3│
└───┴───┴───┴───┘
And now the result we seek is the upper half the triangle. But this approach has drawbacks:
Solutions using {
have similar issues.
The chain
approach would look something like this:
g=. ,"0 i.
(g 0);(g 1);(g 2);(g"0 i.3);<(<@g"0 (1+i.3))
which produces:
┌──┬───┬───┬───┬─────────────┐
│ │1 0│2 0│0 0│┌───┬───┬───┐│
│ │ │2 1│0 0││1 0│2 0│3 0││
│ │ │ │ ││ │2 1│3 1││
│ │ │ │1 0││ │ │3 2││
│ │ │ │0 0│└───┴───┴───┘│
│ │ │ │ │ │
│ │ │ │2 0│ │
│ │ │ │2 1│ │
└──┴───┴───┴───┴─────────────┘
The last two columns are close to what I want, but in the penultimate column we have the nuisance of automatic fill obscuring our result, and in the final column our correct results are boxed, but unboxing them returns the fill.
What is a good (and idiomatically J) way to solve issues like this?
NOTE: I'm not looking for an ad hoc solution to the problem in the example, but a solution to the general problem that is solved by chain
in other languages.
I think that this answer is too specific for what you want, but it does suggest that the solution to part 2 of the challenge (variable length results) is to use each=:&.>
so that the padding can be avoided.
(< 0 1 2 3) ;"1@:((],.>#[) each) 0 1 2 3
0 1
0 2
0 3
1 2
1 3
2 3
(< 0 1 2 3) ((],.>#[) each) 0 1 2 3
+---+---+---+--+
|0 1|1 2|2 3| |
|0 2|1 3| | |
|0 3| | | |
+---+---+---+--+