At least In JMP 10 there is a "Subset by" checkbox. If selected, subsets for every level of selected column(s) are automatically generated. It is easy to implement that function in JSL if the the number of by-columns is known. However, to generalize this was more tricky than I imagined.
This approach, based on inserting the sequentially generated subsets in lists (within lists) seems to work though:
//Example Table
dt = New Table( "Color",
Add Rows( 12 ),
New Column( "Color",
Character,
Nominal,
Set Values( {"red", "red", "red", "red", "blue", "blue", "blue", "blue", "blue", "green", "green", "green"} )
),
New Column( "Intensity",
Character,
Nominal,
Set Values(
{"bright", "bright", "dark", "light", "light", "light", "light", "dark", "dark", "dark", "light", "bright"}
)
),
New Column( "Finish",
Character,
Nominal,
Set Values(
{"Matte", "Blank", "Matte", "Blank", "Matte", "Blank", "Matte", "Blank", "Matte", "Blank", "Matte", "Blank"}
)
),
New Column( "Colensity", Character, Nominal )
);
For Each Row( :Colensity = Color || Intensity || Finish ); // Just for checking that it's working...
// End example table
// Script starts here
cols = {Color, Intensity, Finish}; // Any nr of subset-by-columns (in hierarchical order)
nt = N Table(); //number of currently open tables
subList = Eval List( {dt << subset( by( cols[1] ) )} ); //First-level subsets
//Make lower-level subsets recursively
For( i = 2, i <= N Items( cols ), i++,
Insert Into( subList, Eval List( {Eval( subList[i - 1] ) << subset( by( cols[i] ) )} ) )
);
// name and save the all subsets
myPath = "path"; //change to desired path
For( i = 1, i <= N Table() - nt, i++,
tv = Data Table( i ) << get table variable names; // The levels are stored as table variables
subname = {};
For( j = 1, j <= N Items( tv ), j++,
Insert Into( subname, Data Table( i ) << get table variable( tv[j] ) )
);
Insert Into( subname, dt << get name );
Reverse Into( subname );
Data Table( i ) << save( myPath || Concat Items( subname, "." ) );
);
// End Script //close all(data tables);