ProblemYou have data in one or more lists or matrix vectors that you need to sort.
SolutionUse Sort List() or Sort List Into(), Rank(), or put the lists and vectors in a data table and sort it.
// Sort List example (makes new list)
names = {"fred", "Andy", "Rory", "bess", "susy", "perl"};
sname = Sort List( names );
Show( names, sname );
names = {"fred", "Andy", "Rory", "bess", "susy", "perl"}; // unchanged
sname = {"Andy", "bess", "fred", "perl", "Rory", "susy"}; // sorted // Sort List Into example (in-place sort)
names = {"fred", "Andy", "Rory", "bess", "susy", "perl"};
Sort List Into( names );
Show( names );
names = {"Andy", "bess", "fred", "perl", "Rory", "susy"}; // sorted in-placeBoth examples above operate on a single list. If there is a second list of phone numbers, they don't stick to the names.
To make several lists all have the same sort, you might use the Rank() function. The lists should have the same number of elements and no missing values in the sort-key list.
names = {"fred", "Andy", "Rory", "bess", "susy", "perl"};
phone = {"x321", "x322", "x323", "x324", "x325", "x326"};
rooms = {"1003", "1001", "1005", "1002", "1006", "1004"};
rnk = Rank( names ); // [2, 4, 1, 6, 3, 5]
// use the rnk vector to make sorted lists from the old lists
snames = names[rnk];
sphone = phone[rnk];
srooms = rooms[rnk];
Show( snames, sphone, srooms );
snames = {"Andy", "bess", "fred", "perl", "Rory", "susy"};sphone = {"x322", "x324", "x321", "x326", "x323", "x325"};srooms = {"1001", "1002", "1003", "1004", "1005", "1006"};
Above, the new lists with the prefix s are all sorted by name.
If you have multiple lists, of the same length, but paired across the lists, perhaps a data table would be a better data structure. You might find it easier to use a table because you can see it, save it, subset it, ... But if you have the lists already, you can build a table from them. Here is a re-usable user function that does that:
// the zip function, named after a Python function that, like a zipper, zips two lists together
zip = Function( {variableNameList}, // a list of variable names
{iVarName, dt, data}, // local variables
dt = New Table( "zip", "invisible" ); // a hidden table, returned at end of this function
For( iVarName = 1, iVarName <= N Items( variableNameList ), iVarName += 1,
data = Eval( variableNameList[iVarName] ); // makes a copy of the data from the name
If( Is Matrix( data ) | Is Number( data[1] ), // handle lists of numbers same as a matrix
dt << New Column( Char( variableNameList[iVarName] ), "numeric", values( data ),
setProperty( "wasMatrix", eval(Is Matrix( data ) ) ) ) // remember how to convert back, could be list
, // else a list of strings
dt << New Column( Char( variableNameList[iVarName] ), "character", values( data ),
setProperty( "wasString", eval( Is String( data[1] ) ) ) ) // remember how to convert back, could be names
);
);
dt << New Column( "_original order_", values( 1 :: N Rows( dt ) ) ); // this extra column is not required, but might be useful
dt << setdirty( 0 ); // not required but avoids a "save?" prompt
dt; // return
);
example:
cars = {chevy, volkswagon, honda, ford, toyota}; // list of unquoted names
doors = [4, 2, 2, 5, 2]; // matrix of numbers
miles = {30000, 20000, 40000, 10000, 50000}; // list of numbers
owner = {"fred", "susan", "ralph", "penelope", "terry"}; // list of quoted strings
zippedDt = zip( {cars, doors, miles, owner} );
zippedDt << sort( by( miles ), replacetable( 1 ) );
zippedDt << show Window; // table hidden by default
Lists are in table's columns, sorted by milesIf you are working with lists, you might want all the lists back again. Here's an unzip function:
// unzip, similar to Python's unzip
unzip = Function( {dt}, // data table previously returned from zip (above)
{result, cols, iCol, col, names, iRow}, // local variables
cols = dt << getcolumnnames; // below, the _original order_ col gets skipped
result = {}; // assemble all of the lists and matrices here, return at bottom
For( iCol = 1, iCol < N Items( cols )/*skip last one*/, iCol += 1,
col = Column( dt, cols[icol] ); // the Ith col in the table
If( col << getdatatype( "English" ) == "Numeric", //
// return the same type of object, list or matrix, supplied originally
If( col << getproperty( "wasMatrix" ), // by checking the property we set above
Insert Into( result, col << getValues ); // append a matrix
, // else append a list of numbers
result[N Items( result ) + 1] = As List( dt[0, iCol] )
)
, // else character column
// return same type, list of names or list of strings...
If( col << getproperty( "wasString" ), // check character col prop set above
result[N Items( result ) + 1] = (dt[0, iCol]) // list of strings
, // else turn the strings into names again
result[N Items( result ) + 1] = As Name( dt[0, iCol] ) // list of names
)
);
);
result; // return
);
example:
{cars, doors, miles, owner} = unzip( zippedDt );
List( 4 elements ) assigned.
cars:{ford, volkswagon, chevy, honda, toyota}
doors:[5, 2, 4, 2, 2]
miles:{10000, 20000, 30000, 40000, 50000}
owner:{"penelope", "susan", "fred", "ralph", "terry"}
Finally
// Important! delete the invisible table!
Close( zippedDt, nosave );
DiscussionBe sure to clean up the invisible table if you use the zip/unzip functions. (They are unrelated to the compression function for .zip files. JMP has support for that in the zip archive object.)
The data table is a great tool for complicated data structures. You can make hidden or private tables for managing data without using the wrapper functions above. Lists may be more efficient than data tables if you need to add and remove a lot of items (queues and stacks might be slow if implemented as adding and removing rows from a table.) The zip function (above) expects a list of names. A name (no quotation marks) is not the same as a string (uses quotation marks). Passing a list of names reduces the number of times data is copied.
See Alsohttps://www.jmp.com/support/help/14-2/list-functions.shtml