Optional parameters: Difference between revisions
→{{header|F#}}: added F# |
|||
Line 552: | Line 552: | ||
end program UsingTest</lang> |
end program UsingTest</lang> |
||
=={{header|F_Sharp|F#}}== |
|||
{{trans|Oz}} |
|||
F# supports optional parameters for member functions only, not for free-standing functions. |
|||
Optional parameters are marked by using a question mark in front of the identifier. Their values are passed as option types, i.e. as <code>Some value</code> or <code>None</code>. The helper function <code>defaultArg</code> can be used to specify default values. In the example below, we use shadowing in order to reuse the identifiers <code>ordering</code>, <code>column</code> and <code>reverse</code>. |
|||
<lang fsharp>type Table(rows:string[][]) = |
|||
// in-place sorting of rows |
|||
member x.Sort(?ordering, ?column, ?reverse) = |
|||
let ordering = defaultArg ordering compare |
|||
let column = defaultArg column 0 |
|||
let reverse = defaultArg reverse false |
|||
let factor = if reverse then -1 else 1 |
|||
let comparer (row1:string[]) (row2:string[]) = |
|||
factor * ordering row1.[column] row2.[column] |
|||
Array.sortInPlaceWith comparer rows |
|||
member x.Print() = |
|||
for row in rows do printfn "%A" row |
|||
// Example usage |
|||
let t = new Table([| [|"a"; "b"; "c"|] |
|||
[|""; "q"; "z"|] |
|||
[|"can"; "z"; "a"|] |]) |
|||
printfn "Unsorted"; t.Print() |
|||
t.Sort() |
|||
printfn "Default sort"; t.Print() |
|||
t.Sort(column=2) |
|||
printfn "Sorted by col. 2"; t.Print() |
|||
t.Sort(column=1) |
|||
printfn "Sorted by col. 1"; t.Print() |
|||
t.Sort(column=1, reverse=true) |
|||
printfn "Reverse sorted by col. 1"; t.Print() |
|||
t.Sort(ordering=fun s1 s2 -> compare s2.Length s1.Length) |
|||
printfn "Sorted by decreasing length"; t.Print()</lang> |
|||
=={{header|J}}== |
=={{header|J}}== |
Revision as of 20:00, 15 August 2010
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
Define a function/method/subroutine which sorts a sequence ("table") of sequences ("rows") of strings ("cells"), by one of the strings. Besides the input to be sorted, it shall have the following optional parameters:
- ordering
- A function specifying the ordering of strings; lexicographic by default.
- column
- An integer specifying which string of each row to compare; the first by default.
- reverse
- Reverses the ordering.
This task should be considered to include both positional and named optional parameters, as well as overloading on argument count as in Java or selector name as in Smalltalk, or, in the extreme, using different function names. Provide these variations of sorting in whatever way is most natural to your language. If the language supports both methods naturally, you are encouraged to describe both.
Do not implement a sorting algorithm; this task is about the interface. If you can't use a built-in sort routine, just omit the implementation (with a comment).
See also:
AppleScript
AppleScript supports named, positional & prepositional parameters, but not default or optional parameters. Though that behavior can be simulated by passing lists or records as the parameter. Handler/functions can be passed as a parameter if they are part of a script object. AppleScript does not have built-in sorting functionality. <lang AppleScript>on sortTable(x) set {sortOrdering, sortColumn, sortReverse} to {sort_lexicographic, 1, false} try set sortOrdering to x's ordering end try try set sortColumn to x's column end try try set sortReverse to x's reverse end try return sortOrdering's sort(x's sequence, sortColumn, sortReverse) end sortTable
script sort_lexicographic on sort(table, column, reverse) -- Implement lexicographic Sorting process here. return table end sort end script</lang> Examples of use: <lang AppleScript>-- Another sort function. script sort_colex on sort(table, column, reverse) -- Implement colexicographic Sorting process here. return table end sort end script
-- Populate a table (list) with data. set table to {{1,2},{3,4}}
sortTable({sequence:table, ordering:sort_lexicographic, column:1, reverse:false}) sortTable({sequence:table, ordering:sort_colex, column:2, reverse:true}) sortTable({sequence:table, reverse:true}) sortTable({sequence:table})</lang>
AutoHotkey
built in support for table sorting is available through the standard Win32 listview. <lang AutoHotkey>Gosub start ; create and show the gui sort_table("Text", column := 2, reverse := 1) ; lexicographic sort Sleep, 2000 sort_table("Integer", column := 2, reverse := 1) ; numerical sort Return
start:
Gui, Add, ListView, r20 w200, 1|2|3 data = ( 1,2,3 b,q,z c,z,z ) Loop, Parse, data, `n { StringSplit, row, A_LoopField, `, LV_Add(row, row1, row2, row3) } LV_ModifyCol(50) ; Auto-size columns Gui, Show
Return
- The function supporting named, defaulted arguments
sort_table(ordering = "Text", column = 0, reverse = 0) {
If reverse desc = desc LV_ModifyCol(column, "sort" . desc . " " . ordering)
}
GuiClose:
ExitApp</lang>
BASIC
In Beta BASIC and SAM BASIC, the default values for parameters (or any variable) is given with the keyword DEFAULT.
100 DEF PROC sort_table REF t$(), ordering, col, reverse 110 DEFAULT ordering=0, col=1, reverse=0 120 REM implementation of sort not shown 190 END PROC
Usage example:
500 DIM a$(100,80) 510 REM fill a$ with data here... 550 sort_table a$ 570 sort_table a$, 1, 5, 1
C
<lang c>#include <stdlib.h>
- include <stdarg.h>
- include <stdio.h>
- include <ctype.h>
- include <string.h>
typedef const char * String; typedef struct sTable {
String * *rows; int n_rows,n_cols;
} *Table;
typedef int (*CompareFctn)(String a, String b);
struct {
CompareFctn compare; int column; int reversed;
} sortSpec;
int CmprRows( const void *aa, const void *bb) {
String *rA = *(String **)aa; String *rB = *(String **)bb; int sortCol = sortSpec.column;
String left = sortSpec.reversed ? rB[sortCol] : rA[sortCol]; String right = sortSpec.reversed ? rA[sortCol] : rB[sortCol]; return sortSpec.compare( left, right );
}
/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* tbl parameter is a table of rows of strings * argSpec is a string containing zero or more of the letters o,c,r * if o is present - the corresponding optional argument is a function which * determines the ordering of the strings. * if c is present - the corresponding optional argument is an integer that * specifies the column to sort on. * if r is present - the corresponding optional argument is either * true(nonzero) or false(zero) and if true, the sort will b in reverse order * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int sortTable(Table tbl, const char* argSpec,... ) {
va_list vl; const char *p; int c; sortSpec.compare = &strcmp; sortSpec.column = 0; sortSpec.reversed = 0;
va_start(vl, argSpec); if (argSpec) for (p=argSpec; *p; p++) { switch (*p) { case 'o': sortSpec.compare = va_arg(vl,CompareFctn); break; case 'c': c = va_arg(vl,int); if ( 0<=c && c<tbl->n_cols) sortSpec.column = c; break; case 'r': sortSpec.reversed = (0!=va_arg(vl,int)); break; } } va_end(vl); qsort( tbl->rows, tbl->n_rows, sizeof(String *), &CmprRows); return 0;
}
void printTable( Table tbl, FILE *fout, const char *colFmts[]) {
int row, col;
for (row=0; row<tbl->n_rows; row++) { fprintf(fout, " "); for(col=0; col<tbl->n_cols; col++) { fprintf(fout, colFmts[col], tbl->rows[row][col]); } fprintf(fout, "\n"); } fprintf(fout, "\n");
}
int ord(char v) {
return v-'0';
}
/* an alternative comparison function */ int cmprStrgs(String s1, String s2) {
const char *p1 = s1; const char *p2 = s2; const char *mrk1, *mrk2; while ((tolower(*p1) == tolower(*p2)) && *p1) { p1++; p2++; } if (isdigit(*p1) && isdigit(*p2)) { long v1, v2; if ((*p1 == '0') ||(*p2 == '0')) { while (p1 > s1) { p1--; p2--; if (*p1 != '0') break; } if (!isdigit(*p1)) { p1++; p2++; } } mrk1 = p1; mrk2 = p2; v1 = 0; while(isdigit(*p1)) { v1 = 10*v1+ord(*p1); p1++; } v2 = 0; while(isdigit(*p2)) { v2 = 10*v2+ord(*p2); p2++; } if (v1 == v2) return(p2-mrk2)-(p1-mrk1); return v1 - v2; } if (tolower(*p1) != tolower(*p2)) return (tolower(*p1) - tolower(*p2)); for(p1=s1, p2=s2; (*p1 == *p2) && *p1; p1++, p2++); return (*p1 -*p2);
}
int main() {
const char *colFmts[] = {" %-5.5s"," %-5.5s"," %-9.9s"}; String r1[] = { "a101", "red", "Java" }; String r2[] = { "ab40", "gren", "Smalltalk" }; String r3[] = { "ab9", "blue", "Fortran" }; String r4[] = { "ab09", "ylow", "Python" }; String r5[] = { "ab1a", "blak", "Factor" }; String r6[] = { "ab1b", "brwn", "C Sharp" }; String r7[] = { "Ab1b", "pink", "Ruby" }; String r8[] = { "ab1", "orng", "Scheme" };
String *rows[] = { r1, r2, r3, r4, r5, r6, r7, r8 }; struct sTable table; table.rows = rows; table.n_rows = 8; table.n_cols = 3;
sortTable(&table, ""); printf("sort on col 0, ascending\n"); printTable(&table, stdout, colFmts);
sortTable(&table, "ro", 1, &cmprStrgs); printf("sort on col 0, reverse.special\n"); printTable(&table, stdout, colFmts);
sortTable(&table, "c", 1); printf("sort on col 1, ascending\n"); printTable(&table, stdout, colFmts);
sortTable(&table, "cr", 2, 1); printf("sort on col 2, reverse\n"); printTable(&table, stdout, colFmts); return 0;
}</lang>
C++
This implementation only accepts function pointers for the comparators, and does not accept function objects, for simplicity. <lang cpp>#include <vector>
- include <algorithm>
- include <string>
// helper comparator that is passed to std::sort() template <class T> struct sort_table_functor {
typedef bool (*CompFun)(const T &, const T &); CompFun ordering; int column; bool reverse; sort_table_functor(CompFun o, int c, bool r) : ordering(o), column(c), reverse(r) { } bool operator()(const std::vector<T> &x, const std::vector<T> &y) { const T &a = x[column], &b = y[column]; return reverse ? ordering(b, a) : ordering(a, b); }
};
// natural-order less-than comparator template <class T> bool myLess(const T &x, const T &y) { return x < y; }
// this is the function we call, which takes optional parameters template <class T> void sort_table(std::vector<std::vector<T> > &table,
int column = 0, bool reverse = false, bool (*ordering)(const T &, const T &) = myLess) { std::sort(table.begin(), table.end(), sort_table_functor<T>(ordering, column, reverse));
}
- include <iostream>
// helper function to print our 3x3 matrix template <class T> void print_matrix(std::vector<std::vector<T> > &data) {
for () { for (int j = 0; j < 3; j++) std::cout << data[i][j] << "\t"; std::cout << std::endl; }
}
// order in descending length bool desc_len_comparator(const std::string &x, const std::string &y) {
return x.length() > y.length();
}
int main() {
std::string data_array[3][3] = { {"a", "b", "c"}, {"", "q", "z"}, {"zap", "zip", "Zot"} };
std::vector<std::vector<std::string> > data_orig; for (int i = 0; i < 3; i++) { std::vector<std::string> row; for (int j = 0; j < 3; j++) row.push_back(data_array[i][j]); data_orig.push_back(row); } print_matrix(data_orig);
std::vector<std::vector<std::string> > data = data_orig; sort_table(data); print_matrix(data);
data = data_orig; sort_table(data, 2); print_matrix(data);
data = data_orig; sort_table(data, 1); print_matrix(data);
data = data_orig; sort_table(data, 1, true); print_matrix(data);
data = data_orig; sort_table(data, 0, false, desc_len_comparator); print_matrix(data);
return 0;
}</lang>
Common Lisp
Common Lisp has both named and positional parameters. The following example shows optional named parameters, using the &key
keyword. Optional positional parameters are specified using the &optional
keyword.
<lang lisp>(defun sort-table (table &key (ordering #'string<)
(column 0) reverse) (sort table (if reverse (complement ordering) ordering) :key (lambda (row) (elt row column))))</lang>
(Notes: The builtin sort takes a "less than" predicate function. The complement function inverts a predicate.)
Example uses: <lang lisp>CL-USER> (defparameter *data* '(("a" "b" "c") ("" "q" "z") ("zap" "zip" "Zot")))
- DATA*
CL-USER> (sort-table *data*) (("" "q" "z") ("a" "b" "c") ("zap" "zip" "Zot"))
CL-USER> (sort-table *data* :column 2) (("zap" "zip" "Zot") ("a" "b" "c") ("" "q" "z"))
CL-USER> (sort-table *data* :column 1) (("a" "b" "c") ("" "q" "z") ("zap" "zip" "Zot"))
CL-USER> (sort-table *data* :column 1 :reverse t) (("zap" "zip" "Zot") ("" "q" "z") ("a" "b" "c"))
CL-USER> (sort-table *data* :ordering (lambda (a b) (> (length a) (length b)))) (("zap" "zip" "Zot") ("a" "b" "c") ("" "q" "z"))</lang>
E
In E, as in Java and Smalltalk, optional parameters are defined as different methods with the same base name. Methods are distinguished by name (verb) and number of parameters (arity).
<lang e>def defaultOrdering(a, b) { return a.op__cmp(b) }
def sort {
to run(table) { return sort(table, 0, false, defaultOrdering) } to run(table, column) { return sort(table, column, false, defaultOrdering) } to run(table, column, reverse) { return sort(table, column, reverse, defaultOrdering) }
to run(table :List[List[String]], column :int, reverse :boolean, ordering) { return table.sort(fn a, b { def ord := ordering(a[column], b[column]) if (reverse) { -ord } else { ord } }) }
}</lang>
Named parameters are not builtin, but map-patterns may be used as a substitute. (TODO: Example of this)
Fortran
In Fortran, each argument has its "name". The optional attribute can be used to specify that an argument is optional, and its presence (or absence) can be tested using the present intrinsic (so that we can give a default value, or execute accordingly a totally different code).
<lang fortran>module ExampleOptionalParameter
! use any module needed for the sort function(s) ! and all the interfaces needed to make the code work implicit none
contains
subroutine sort_table(table, ordering, column, reverse) type(table_type), intent(inout) :: table integer, optional :: column logical, optional :: reverse optional :: ordering interface integer function ordering(a, b) type(table_element), intent(in) :: a, b end function ordering end interface
integer :: the_column, i logical :: reversing type(table_row) :: rowA, rowB
if ( present(column) ) then if ( column > get_num_of_columns(table) ) then ! raise an error? else the_column = column end if else the_column = 1 ! a default value, de facto end if
reversing = .false. ! default value if ( present(reverse) ) reversing = reverse
do ! loops over the rows to sort... at some point, we need ! comparing an element (cell) of the row, with the element ! in another row; ... let us suppose rowA and rowB are ! the two rows we are considering ea = get_element(rowA, the_column) eb = get_element(rowB, the_column) if ( present(ordering) ) then if ( .not. reversing ) then if ( ordering(ea, eb) > 0 ) then ! swap the rowA with the rowB end if else ! < instead of > if ( ordering(ea, eb) < 0 ) then ! swap the rowA with the rowB end if end if else if ( .not. reversing ) then if ( lexinternal(ea, eb) > 0 ) then ! swap the rowA with the rowB end if else ! < instead of > if ( lexinternal(ea, eb) < 0 ) then ! swap the rowA with the rowB end if end if end if ! ... more of the sorting algo ... ! ... and rows traversing ... (and an exit condition of course!) end do
end subroutine sort_table
end module ExampleOptionalParameter</lang>
<lang fortran>program UsingTest
use ExampleOptionalParameter implicit none
type(table_type) :: table
! create the table...
! sorting taking from column 1, not reversed, using internal ! default comparator call sort_table(table)
! the same as above, but in reversed order; we MUST specify ! the name of the argument since it is not given in the same ! order of the subroutine spec call sort_table(table, reverse=.true.)
! sort the table using a custom comparator call sort_table(table, my_cmp) ! or call sort_table(table, ordering=my_cmp)
! as above, but taking from column 2 call sort_table(table, my_cmp, 2) ! or (swapping the order of args for fun) call sort_table(table, column=2, ordering=my_cmp)
! with custom comparator, column 2 and reversing... call sort_table(table, my_cmp, 2, .true.) ! of course we can swap the order of optional args ! by prefixing them with the name of the arg
! sort from column 2, with internal comparator call sort_table(table, column=2)
end program UsingTest</lang>
F#
F# supports optional parameters for member functions only, not for free-standing functions.
Optional parameters are marked by using a question mark in front of the identifier. Their values are passed as option types, i.e. as Some value
or None
. The helper function defaultArg
can be used to specify default values. In the example below, we use shadowing in order to reuse the identifiers ordering
, column
and reverse
.
<lang fsharp>type Table(rows:string[][]) =
// in-place sorting of rows member x.Sort(?ordering, ?column, ?reverse) = let ordering = defaultArg ordering compare let column = defaultArg column 0 let reverse = defaultArg reverse false
let factor = if reverse then -1 else 1 let comparer (row1:string[]) (row2:string[]) = factor * ordering row1.[column] row2.[column]
Array.sortInPlaceWith comparer rows member x.Print() = for row in rows do printfn "%A" row
// Example usage let t = new Table([| [|"a"; "b"; "c"|]
[|""; "q"; "z"|] [|"can"; "z"; "a"|] |])
printfn "Unsorted"; t.Print()
t.Sort() printfn "Default sort"; t.Print()
t.Sort(column=2) printfn "Sorted by col. 2"; t.Print()
t.Sort(column=1) printfn "Sorted by col. 1"; t.Print()
t.Sort(column=1, reverse=true) printfn "Reverse sorted by col. 1"; t.Print()
t.Sort(ordering=fun s1 s2 -> compare s2.Length s1.Length) printfn "Sorted by decreasing length"; t.Print()</lang>
J
<lang J>srtbl=: verb define
srtbl y
'`ordering column reverse'=. x (3{. [, ]}.~ #@[) ]`0:`0: |.^:reverse y /: ordering (column {"1 ])y
)</lang>
For simplicity, the optional arguments are all functions, and are positional (on the left -- the table, with its arbitrary number of rows and columns, is on the right). Note also that the ordering function is expected to map its entire argument (since this offers much better efficiencies than a binary comparison).
Java
Java has no optional parameters, but methods can be overloaded on the number and types of arguments, which can be used to effectively achieve optional positional parameters.
<lang java>import java.util.*;
public class OptionalParams {
// "natural ordering" comparator static <T extends Comparable<? super T>> Comparator<T> naturalOrdering() { return Collections.reverseOrder(Collections.<T>reverseOrder()); }
public static <T extends Comparable<? super T>> void sortTable(T[][] table) { sortTable(table, 0); } public static <T extends Comparable<? super T>> void sortTable(T[][] table, int column) { sortTable(table, column, false); } public static <T extends Comparable<? super T>> void sortTable(T[][] table, int column, boolean reverse) { sortTable(table, column, reverse, OptionalParams.<T>naturalOrdering()); } public static <T> void sortTable(T[][] table, final int column, final boolean reverse, final Comparator<T> ordering) { Comparator<T[]> myCmp = new Comparator<T[]>() { public int compare(T[] x, T[] y) { return (reverse ? -1 : 1) * ordering.compare(x[column], y[column]); } }; Arrays.sort(table, myCmp); }
public static void main(String[] args) { String[][] data0 = {{"a", "b", "c"}, {"", "q", "z"}, {"zap", "zip", "Zot"}}; System.out.println(Arrays.deepToString(data0)); // prints: [[a, b, c], [, q, z], [zap, zip, Zot]]
// we copy it so that we don't change the original copy String[][] data = data0.clone(); sortTable(data); System.out.println(Arrays.deepToString(data)); // prints: [[, q, z], [a, b, c], [zap, zip, Zot]]
data = data0.clone(); sortTable(data, 2); System.out.println(Arrays.deepToString(data)); // prints: [[zap, zip, Zot], [a, b, c], [, q, z]]
data = data0.clone(); sortTable(data, 1); System.out.println(Arrays.deepToString(data)); // prints: [[a, b, c], [, q, z], [zap, zip, Zot]]
data = data0.clone(); sortTable(data, 1, true); System.out.println(Arrays.deepToString(data)); // prints: [[zap, zip, Zot], [, q, z], [a, b, c]]
data = data0.clone(); sortTable(data, 0, false, new Comparator<String>() { public int compare(String a, String b) { return b.length() - a.length(); } }); System.out.println(Arrays.deepToString(data)); // prints: [[zap, zip, Zot], [a, b, c], [, q, z]] }
}</lang>
JavaScript
See Named parameters#JavaScript, to pass named parameters one uses an object with properties set: <lang javascript>function sorter(table, options) {
opts = {} opts.ordering = options.ordering || 'lexicographic'; opts.column = options.column || 0; opts.reverse = options.reverse || false; // ...
}
sorter(the_data, {reverse: true, ordering: 'numeric'});</lang>
Logo
<lang logo>to sort :table [:column 1] [:ordering "before?] [:reverse "false]
; ...
end</lang> The function "sort" has a default arity of 1 for the required parameter. When overriding default parameters, you must wrap the call in parentheses to specify the different arity. <lang logo>sort :table (sort :table 2) (sort :table 3 "less? "true)</lang>
OCaml
OCaml has optional named parameters. It is conventional to place a non-optional parameter after the optional parameters, because if the optional parameters were at the end, then if you don't provide them, it will just look like a partial application (because OCaml supports currying), resulting in a function which still expects the optional parameters.
<lang ocaml>let sort_table ?(ordering = compare) ?(column = 0) ?(reverse = false) table =
let cmp x y = ordering (List.nth x column) (List.nth y column) * (if reverse then -1 else 1) in List.sort cmp table</lang>
Example uses: <lang ocaml># let data = [["a"; "b"; "c"]; [""; "q"; "z"]; ["zap"; "zip"; "Zot"]];; val data : string list list =
[["a"; "b"; "c"]; [""; "q"; "z"]; ["zap"; "zip"; "Zot"]]
- sort_table data;;
- : string list list = [[""; "q"; "z"]; ["a"; "b"; "c"]; ["zap"; "zip"; "Zot"]]
- sort_table ~column:2 data;;
- : string list list = [["zap"; "zip"; "Zot"]; ["a"; "b"; "c"]; [""; "q"; "z"]]
- sort_table ~column:1 data;;
- : string list list = [["a"; "b"; "c"]; [""; "q"; "z"]; ["zap"; "zip"; "Zot"]]
- sort_table ~column:1 ~reverse:true data;;
- : string list list = [["zap"; "zip"; "Zot"]; [""; "q"; "z"]; ["a"; "b"; "c"]]
- sort_table ~ordering:(fun a b -> compare (String.length b) (String.length a)) data;;
- : string list list = [["zap"; "zip"; "Zot"]; ["a"; "b"; "c"]; [""; "q"; "z"]]</lang>
OCaml does not support optional positional parameters, because, since OCaml supports currying, it would conflict with partial applications, where you do not provide all the arguments to a function, and it results in a function which expects the remaining arguments.
Oz
Oz supports optional parameters only for methods, not for functions. <lang oz>declare
class Table attr rows
meth init(Rows) rows := Rows end
meth sort(ordering:O<=Lexicographic column:C<=1 reverse:R<=false) fun {Predicate Row1 Row2} Res = {O {Nth Row1 C} {Nth Row2 C}} in if R then {Not Res} else Res end end in rows := {Sort @rows Predicate} end end
fun {Lexicographic As Bs} %% omitted for brevity end
T = {New Table init([["a" "b" "c"] ["" "q" "z"] ["zap" "zip" "Zot"]])}
in
{T sort} {T sort(column:3)} {T sort(column:2)} {T sort(column:2 reverse:true)} {T sort(ordering:fun {$ A B} {Length B} < {Length A} end)}</lang>
Perl
Perl has no formal parameters, so all function arguments must be processed in the function body.
This function expects its first argument to be a reference to an array of arrays. It interprets any remaining arguments as a hash of optional parameters.
<lang perl>sub sorttable
{my @table = @{shift()}; my %opt = (ordering => sub {$_[0] cmp $_[1]}, column => 0, reverse => 0, @_); my $col = $opt{column}; my $func = $opt{ordering}; my @result = sort {$func->($a->[$col], $b->[$col])} @table; return ($opt{reverse} ? [reverse @result] : \@result);}</lang>
An example of use:
<lang perl>my $a = [["a", "b", "c"], ["", "q", "z"], ["zap", "zip", "Zot"]]; foreach (@{sorttable $a, column => 1, reverse => 1})
{foreach (@$_) {printf "%-5s", $_;} print "\n";}</lang>
PicoLisp
<lang PicoLisp>(de sortTable (Tbl . @)
(let (Ordering prog Column 1 Reverse NIL) # Set defaults (bind (rest) # Bind optional params (setq Tbl (by '((L) (Ordering (get L Column))) sort Tbl ) ) (if Reverse (flip Tbl) Tbl) ) ) )</lang>
Output:
(de *Data ("a" "bcdef" "X") (" " "qrst" "z") ("zap" "zip" "Zot")) : (sortTable *Data) -> ((" " "qrst" "z") ("a" "bcdef" "X") ("zap" "zip" "Zot")) : (sortTable *Data '(Reverse . T)) -> (("zap" "zip" "Zot") ("a" "bcdef" "X") (" " "qrst" "z")) : (sortTable *Data '(Column . 2) '(Ordering . length)) -> (("zap" "zip" "Zot") (" " "qrst" "z") ("a" "bcdef" "X")) : (sortTable *Data '(Ordering . uppc) '(Column . 3)) -> (("a" "bcdef" "X") (" " "qrst" "z") ("zap" "zip" "Zot"))
Python
only (the "cmp" argument to sorted() is no longer accepted in Python 3)
Using a pretty-printer for the table <lang python>>>> def printtable(data):
for row in data: print ' '.join('%-5s' % ('"%s"' % cell) for cell in row)
>>> import operator
>>> def sorttable(table, ordering=None, column=0, reverse=False):
return sorted(table, cmp=ordering, key=operator.itemgetter(column), reverse=reverse)
>>> data = [["a", "b", "c"], ["", "q", "z"], ["zap", "zip", "Zot"]] >>> printtable(data) "a" "b" "c" "" "q" "z" "zap" "zip" "Zot" >>> printtable( sorttable(data) ) "" "q" "z" "a" "b" "c" "zap" "zip" "Zot" >>> printtable( sorttable(data, column=2) ) "zap" "zip" "Zot" "a" "b" "c" "" "q" "z" >>> printtable( sorttable(data, column=1) ) "a" "b" "c" "" "q" "z" "zap" "zip" "Zot" >>> printtable( sorttable(data, column=1, reverse=True) ) "zap" "zip" "Zot" "" "q" "z" "a" "b" "c" >>> printtable( sorttable(data, ordering=lambda a,b: cmp(len(b),len(a))) ) "zap" "zip" "Zot" "a" "b" "c" "" "q" "z" >>></lang>
See the Python entry in Named Arguments for a more comprehensive description of Python function parameters and call arguments.
Note that expression for a default argument of an optional parameter is evaluated only once, when the function definition is executed, and all calls of the function where that parameter is missing will be initialized to point to that same shared object. So, if the default argument value is a mutable object (e.g. list, dict, etc.), then any changes to it will affect what is seen by future calls of the function:
>>> def foo(x, lst=[]): ... lst.append(x) ... print lst ... >>> foo(1) [1] >>> foo(2) [1, 2] >>> foo(3) [1, 2, 3]
R
Optional parameters are given using a name=value syntax within the function header. <lang R>tablesort <- function(x, ordering="lexicographic", column=1, reverse=false) {
# Implementation
}
- Usage is e.g.
tablesort(mytable, column=3)</lang>
Ruby
Ruby does provide a mechanism to specify default values for method arguments: <lang ruby>def tablesort(table, ordering=:sort_proc, column=0, reverse=false)
# ...</lang>
However, you cannot pass named parameters: if you want to pass "reverse=true", you must also give values for ordering and column.
The idiomatic way in Ruby is to pass a hash or name=>value pairs as method arguments, like this: <lang ruby>def tablesort(table, options={})
# provide default values then merge in user's options opts = {"ordering" => :sort_proc, "column" => 0, "reverse" => false}.merge(options)
# ... rest of code, for example: opts.each_pair {|name, value| puts "#{name} => #{value}"}
end
tablesort(data, "reverse" => true, "column" => 3)</lang>
Scala
With Scala 2.8 optional and named parameters are build in. <lang scala>def sortTable(data:List[List[String]], ordering:(String, String)=>Boolean =(_<_),
column:Int =0, reverse:Boolean =false)={ val result=data.sortWith((a, b)=> ordering(a(column), b(column))) if(reverse) result.reverse else result
}</lang> <lang scala>val data=List(List("a","b","c"), List("","q","z"), List("zap","zip","Zot")) println(data)
//-> List(List(a, b, c), List(, q, z), List(zap, zip, Zot))
println(sortTable(data))
//-> List(List(, q, z), List(a, b, c), List(zap, zip, Zot))
println(sortTable(data, reverse=true))
//-> List(List(zap, zip, Zot), List(a, b, c), List(, q, z))
println(sortTable(data, column=2))
//-> List(List(zap, zip, Zot), List(a, b, c), List(, q, z))
println(sortTable(data, ((a, b)=> b.size<a.size)))
//-> List(List(zap, zip, Zot), List(a, b, c), List(, q, z))</lang>
Slate
In Slate, named optional parameters may be specified in the method signature, but not defaults, so there is a macro defaultsTo: for specifying that within the method body at run-time. <lang slate>s@(Sequence traits) tableSort &column: column &sortBy: sortBlock &reverse: reverse [
column `defaultsTo: 0. sortBlock `defaultsTo: [| :a :b | (a lexicographicallyCompare: b) isNegative]. reverse `defaultsTo: False. reverse ifTrue: [sortBlock: [| :a :b | (sortBlock applyTo: {a. b}) not]]. s sortBy: [| :a :b | sortBlock applyTo: {a at: column. b at: column}]
].</lang>
Tcl
Tcl supports optional parameters to procedures through two mechanisms. It can either work positionally (through giving default values for arguments) or by using a special last argument called “args
” which will collect all the remaining arguments into a list that can be processed by the procedure.
The optional positional parameter style works like this:
<lang tcl>proc tablesort {table {ordering ""} {column 0} {reverse 0}} {
set direction [expr {$reverse ? "-decreasing" : "-increasing"}] if {$ordering ne ""} { lsort -command $ordering $direction -index $column $table } else { lsort $direction -index $column $table }
}
puts [tablesort $data] puts [tablesort $data "" 1] puts [tablesort $data "" 0 1] puts [tablesort $data {
apply {{a b} {expr {[string length $a]-[string length $b]}}}
}]</lang>
When using the second style, it is often common to use Named Arguments (and in fact the “lsort
” already works very much like this). Note that it is most common to use named arguments that start with a “-
”, but we omit them here so that we formally match the requirements of the task.
<lang Tcl>package require Tcl 8.5; # Only for the list expansion syntax
proc tablesort {table args} {
array set opt {ordering "" column 0 reverse 0} array set opt $args set pars [list -index $opt(column)] if {$opt(reverse)} {lappend pars -decreasing} if {$opt(ordering) ne ""} {lappend pars -command $opt(ordering)} lsort {*}$pars $table
}
puts [tablesort $data] puts [tablesort $data column 1] puts [tablesort $data column 0] puts [tablesort $data column 0 reverse 1] puts [tablesort $data ordering {
apply {{a b} {expr {[string length $b]-[string length $a]}}}
}]</lang>
Ursala
Because functions in Ursala take only a single argument and the usual programming style is point free, the most natural way of affecting named optional function parameters is to parameterize the function by a record with computed fields. Fields in a record instance can be associated with descriptive identifiers, listed in any order, and omitted if their default values are intended.
For this task, a record type ss
(for sort specification) is defined
with three fields, ordering
, column
, and reversed
. The ordering
field
contains a binary relational predicate, with the lexicographic
relation (lleq
) being the default. The column
field is a natural number with
a default value of 1, and the reversed
field is a boolean with a
default value of false.
The sorter
is actually a second order function taking a record of
this type as an argument, and returning a function built to order
that is applicable to a list of data to be sorted.
<lang Ursala>#import std
- import nat
ss ::
ordering %fZ ~ordering||lleq! column %n ~column||1! reversed %b
sorter = +^(~reversed?/~&x! ~&!,-<+ +^/~ordering ~~+ ~&h++ //skip+ predecessor+ ~column)</lang> Here is a test program using the function above to sort a table five different ways, mentioning only the information that differs from the defaults. The table is stored as a list of lists, with one list for each row, hence three rows and two columns. <lang Ursala>example_table =
<
<'foo','b '>, <'barr','a '>, <'bazzz','c'>>
- cast %sLLL
examples =
<
(sorter ss&) example_table, # default sorting algorithm (sorter ss[ordering: leql]) example_table, # sort by field lengths but otherwise default (sorter ss[column: 2]) example_table, # etc. (sorter ss[reversed: true]) example_table, (sorter ss[reversed: true,column: 2]) example_table></lang>
In practice, these five functions would have been more conveniently expressed using the
built in sort operator as -<&h
, leql-<&h
, -<&th
, -<x&h
, and -<x&th
respectively, but this technique is useful in more complicated applications.
Here is the output showing five different sorts of the table.
< <<'barr','a '>,<'bazzz','c'>,<'foo','b '>>, <<'foo','b '>,<'barr','a '>,<'bazzz','c'>>, <<'barr','a '>,<'foo','b '>,<'bazzz','c'>>, <<'foo','b '>,<'bazzz','c'>,<'barr','a '>>, <<'bazzz','c'>,<'foo','b '>,<'barr','a '>>>
XSLT
You can give any template parameter a default value using the optional "select" attribute. <lang xml><xsl:template name="sort">
<xsl:param name="table" /> <xsl:param name="ordering" select="'lexicographic'" /> <xsl:param name="column" select="1" /> <xsl:param name="reversed" select="false()" /> ...
</xsl:template></lang>