How to pass pointer to a container from function? - raku
I can bind containers to new names:
my %h;
my $p := %h{ "a" }{ "b" }{ "c" };
$p = 1;
say %h;
Which outputs expected:
{a => {b => {c => 1}}}
But what if I need to return such pointer from subroutine?
my %h;
sub get-pointer {
my $p := %h{ "a" }{ "b" }{ "c" };
return $p;
};
my $q := get-pointer();
$q = 1;
say %h;
Gives:
Cannot assign to a readonly variable or a value
That thing puzzles me - $p.WHERE and $q.WHERE give the same address, so why is it suddenly read-only?
Nevermind, I had some tunnel-vision moment and wanted aliases to behave as C pointers.
Found it clearly explained here at Raku Documentation.
The sub return will return values, not containers. Those are immutable
To return a mutable container, use return-rw.
Related
How to flatten or stringify an object (esp. Match)?
How do we flatten or stringify Match (or else) object to be string data type (esp. in multitude ie. as array elements)? e.g. 'foobar' ~~ m{ (foo) }; say $0.WHAT; my $foo = $0; say $foo.WHAT (Match) (Match) How to end up with (Str)?
~ is the Str contextualizer: 'foobar' ~~ m{ (foo) }; say ~$0 will directly coerce it to a Str. You can use that if you have many matches, i. e.: 'foobar' ~~ m{ (f)(o)(o) }; say $/.map: ~*; # (f o o)
Just treat the objects as if they were strings. If you apply a string operation to a value/object Raku will almost always just automatically coerce it to a string. String operations include functions such as print and put, operators such as infix eq and ~ concatenation, methods such as .starts-with or .chop, interpolation such as "A string containing a $variable", and dedicated coercers such as .Str and Str(...). A Match object contains an overall match. Any "children" (sub-matches) are just captures of substrings of that overall match. So there's no need to flatten anything because you can just deal with the single overall match. A list of Match objects is a list. And a list is itself an object. If you apply a string operation to a list, you get the elements of the list stringified with a space between each element. So: 'foobar' ~~ m{ (f) (o) (o) }; put $/; # foo put $/ eq 'foo'; # True put $/ ~ 'bar'; # foobar put $/ .chop; # fo put "[$/]"; # [foo] put $/ .Str; # foo my Str() $foo = $/; say $foo.WHAT; # (Str) put 'foofoo' ~~ m:g{ (f) (o) (o) }; # foo foo
The constructor for Str takes any Cool value as argument, including a regex Match object. 'foobar' ~~ m{ (foo) }; say $0.WHAT; # (Match) say $0.Str.WHAT; # (Str)
perl6 Unable to initialize a state variable. Help needed
I want to use a one-liner to print a middle section of a file by using a state variable to indicate whether the current line is within the desired section of the file. But I am unable to initialize the state variable. Initialization is so simple, and I just cannot find what the problem is. Please help. Thanks. The file is name testFile.txt and has the following lines: section 0; state 0; not needed = start section 1 = state 1; needed = end section 1 = section 2; state 2; not needed And my one-liner is cat testFile.txt | perl6 -ne ' state $x = 0; say "$x--> "; if $_ ~~ m/ "start" / { $x=1; }; if $x == 1 { .say; }; if $_ ~~ m/ "end" / { $x = 2; }' And the output showed that $x=0 is not doing initialization: Use of uninitialized value $x of type Any in string context. Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful. in block at -e line 1 --> Use of uninitialized value of type Any in numeric context in block at -e line 1 Use of uninitialized value $x of type Any in string context. Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful. in block at -e line 1 --> = start section 1 = 1--> state 1; needed 1--> = end section 1 = 2--> 2-->
This looks like a bug to me: Apparently, -n does not properly set up a lexical environment. As a workaround, you can wrap the whole things in a block, eg by surrounding your code with do { ... } or even just { ... }. Also note that depending on your use case, the whole thing can probably be simplified by using the flip-flop operator, eg cat testFile.txt | perl6 -ne '.say if / "start" / ff / "end" /'
awk count selective combinations only:
Would like to read and count the field value == "TRUE" only from 3rd field to 5th field. Input.txt Locationx,Desc,A,B,C,Locationy ab123,Name1,TRUE,TRUE,TRUE,ab1234 ab123,Name2,TRUE,FALSE,TRUE,ab1234 ab123,Name2,FALSE,FALSE,TRUE,ab1234 ab123,Name1,TRUE,TRUE,TRUE,ab1234 ab123,Name2,TRUE,TRUE,TRUE,ab1234 ab123,Name3,FALSE,FALSE,FALSE,ab1234 ab123,Name3,TRUE,FALSE,FALSE,ab1234 ab123,Name3,TRUE,TRUE,FALSE,ab1234 ab123,Name3,TRUE,TRUE,FALSE,ab1234 ab123,Name1,TRUE,TRUE,FALSE,ab1234 While reading the headers from 3rd field to 5th field , i,e A, B, C want to generate unique combinations and permutations like A,B,C,AB,AC,AB,ABC only. Note: AA, BB, CC, BA etc excluded If the "TRUE" is considered for "AB" combination count then it should not be considered for "A" conut & "B" count again to avoid duplicate .. Example#1 Locationx,Desc,A,B,C,Locationy ab123,Name1,TRUE,TRUE,TRUE,ab1234 Op#1 Desc,A,B,C,AB,AC,BC,ABC Name1,,,,,,,1 Example#2 Locationx,Desc,A,B,C,Locationy ab123,Name1,TRUE,TRUE,FALSE,ab1234 Op#2 Desc,A,B,C,AB,AC,BC,ABC Name1,,,,1,,, Example#3 Locationx,Desc,A,B,C,Locationy ab123,Name1,FALSE,TRUE,FALSE,ab1234 Op#3 Desc,A,B,C,AB,AC,BC,ABC Name1,,1,,,,, Desired Output: Desc,A,B,C,AB,AC,BC,ABC Name1,,,,1,,,2 Name2,,,1,,1,,1 Name3,1,,,2,,, Actual File is like below : Input.txt Locationx,Desc,INCOMING,OUTGOING,SMS,RECHARGE,DEBIT,DATA,Locationy ab123,Name1,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE,ab1234 ab123,Name2,TRUE,TRUE,FALSE,TRUE,TRUE,TRUE,ab1234 ab123,Name2,TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,ab1234 ab123,Name1,TRUE,TRUE,TRUE,TRUE,FALSE,TRUE,ab1234 ab123,Name2,TRUE,TRUE,TRUE,TRUE,FALSE,TRUE,ab1234 ab123,Name3,FALSE,FALSE,FALSE,TRUE,FALSE,FALSE,ab1234 ab123,Name3,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,ab1234 ab123,Name3,TRUE,TRUE,FALSE,TRUE,FALSE,FALSE,ab1234 ab123,Name3,TRUE,TRUE,FALSE,TRUE,FALSE,FALSE,ab1234 ab123,Name1,TRUE,TRUE,FALSE,FALSE,FALSE,TRUE,ab1234 Have tried lot , nothing is materialised , any suggestions please !!! Edit: Desired Output from Actual Input: Desc,INCOMING-OUTGOING-SMS-RECHARGE-DEBIT-DATA,OUTGOING-SMS-RECHARGE-DEBIT-DATA,INCOMING-SMS-RECHARGE-DEBIT-DATA,INCOMING-OUTGOING-RECHARGE-DEBIT-DATA,INCOMING-OUTGOING-SMS-RECHARGE-DATA,INCOMING-OUTGOING-SMS-RECHARGE-DEBIT,SMS-RECHARGE-DEBIT-DATA,OUTGOING-RECHARGE-DEBIT-DATA,OUTGOING-SMS-RECHARGE-DATA,OUTGOING-SMS-RECHARGE-DEBIT,INCOMING-RECHARGE-DEBIT-DATA,INCOMING-SMS-DEBIT-DATA,INCOMING-SMS-RECHARGE-DATA,INCOMING-SMS-RECHARGE-DEBIT,INCOMING-OUTGOING-DEBIT-DATA,INCOMING-OUTGOING-RECHARGE-DATA,INCOMING-OUTGOING-RECHARGE-DEBIT,INCOMING-OUTGOING-SMS-DATA,INCOMING-OUTGOING-SMS-DEBIT,INCOMING-OUTGOING-SMS-RECHARGE,RECHARGE-DEBIT-DATA,SMS-DEBIT-DATA,SMS-RECHARGE-DATA,SMS-RECHARGE-DEBIT,OUTGOING-RECHARGE-DATA,OUTGOING-RECHARGE-DEBIT,OUTGOING-SMS-DATA,OUTGOING-SMS-DEBIT,OUTGOING-SMS-RECHARGE,INCOMING-DEBIT-DATA,INCOMING-RECHARGE-DATA,INCOMING-RECHARGE-DEBIT,INCOMING-SMS-DATA,INCOMING-SMS-DEBIT,INCOMING-SMS-RECHARGE,INCOMING-OUTGOING-DATA,INCOMING-OUTGOING-DEBIT,INCOMING-OUTGOING-RECHARGE,INCOMING-OUTGOING-SMS,DEBIT-DATA,RECHARGE-DATA,RECHARGE-DEBIT,SMS-DATA,SMS-DEBIT,SMS-RECHARGE,OUTGOING-DATA,OUTGOING-DEBIT,OUTGOING-RECHARGE,OUTGOING-SMS,INCOMING-DATA,INCOMING-DEBIT,INCOMING-RECHARGE,INCOMING-SMS,INCOMING-OUTGOING,DATA,DEBIT,RECHARGE,SMS,OUTGOING,INCOMING Name1,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,1,,,,,,,,,,,,,,,,,,,,, Name2,,,,1,1,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, Name3,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,1,,, Don't have Perl and Python access !!!
I have written a perl script that does this for you. As you can see from the size and comments, it is really simple to get this done. #!/usr/bin/perl use strict; use warnings; use autodie; use Algorithm::Combinatorics qw(combinations); ## change the file to the path where your file exists open my $fh, '<', 'file'; my (%data, #new_labels); ## capture the header line in an array my #header = split /,/, <$fh>; ## backup the header my #fields = #header; ## remove first, second and last columns #header = splice #header, 2, -1; ## generate unique combinations for my $iter (1 .. +#header) { my $combination = combinations(\#header, $iter); while (my $pair = $combination->next) { push #new_labels, "#$pair"; } } ## iterate through rest of the file while(my $line = <$fh>) { my #line = split /,/, $line; ## identify combined labels that are true my #is_true = map { $fields[$_] } grep { $line[$_] eq "TRUE" } 0 .. $#line; ## increment counter in hash map keyed at description and then new labels ++$data{$line[1]}{$_} for map { s/ /-/g; $_ } "#is_true"; } ## print the new header print join ( ",", "Desc", map {s/ /-/g; $_} reverse #new_labels ) . "\n"; ## print the description and counter values for my $desc (sort keys %data){ print join ( ",", $desc, ( map { $data{$desc}{$_} //= "" } reverse #new_labels ) ) . "\n"; } Output: Desc,INCOMING-OUTGOING-SMS-RECHARGE-DEBIT-DATA,OUTGOING-SMS-RECHARGE-DEBIT-DATA,INCOMING-SMS-RECHARGE-DEBIT-DATA,INCOMING-OUTGOING-RECHARGE-DEBIT-DATA,INCOMING-OUTGOING-SMS-DEBIT-DATA,INCOMING-OUTGOING-SMS-RECHARGE-DATA,INCOMING-OUTGOING-SMS-RECHARGE-DEBIT,SMS-RECHARGE-DEBIT-DATA,OUTGOING-RECHARGE-DEBIT-DATA,OUTGOING-SMS-DEBIT-DATA,OUTGOING-SMS-RECHARGE-DATA,OUTGOING-SMS-RECHARGE-DEBIT,INCOMING-RECHARGE-DEBIT-DATA,INCOMING-SMS-DEBIT-DATA,INCOMING-SMS-RECHARGE-DATA,INCOMING-SMS-RECHARGE-DEBIT,INCOMING-OUTGOING-DEBIT-DATA,INCOMING-OUTGOING-RECHARGE-DATA,INCOMING-OUTGOING-RECHARGE-DEBIT,INCOMING-OUTGOING-SMS-DATA,INCOMING-OUTGOING-SMS-DEBIT,INCOMING-OUTGOING-SMS-RECHARGE,RECHARGE-DEBIT-DATA,SMS-DEBIT-DATA,SMS-RECHARGE-DATA,SMS-RECHARGE-DEBIT,OUTGOING-DEBIT-DATA,OUTGOING-RECHARGE-DATA,OUTGOING-RECHARGE-DEBIT,OUTGOING-SMS-DATA,OUTGOING-SMS-DEBIT,OUTGOING-SMS-RECHARGE,INCOMING-DEBIT-DATA,INCOMING-RECHARGE-DATA,INCOMING-RECHARGE-DEBIT,INCOMING-SMS-DATA,INCOMING-SMS-DEBIT,INCOMING-SMS-RECHARGE,INCOMING-OUTGOING-DATA,INCOMING-OUTGOING-DEBIT,INCOMING-OUTGOING-RECHARGE,INCOMING-OUTGOING-SMS,DEBIT-DATA,RECHARGE-DATA,RECHARGE-DEBIT,SMS-DATA,SMS-DEBIT,SMS-RECHARGE,OUTGOING-DATA,OUTGOING-DEBIT,OUTGOING-RECHARGE,OUTGOING-SMS,INCOMING-DATA,INCOMING-DEBIT,INCOMING-RECHARGE,INCOMING-SMS,INCOMING-OUTGOING,DATA,DEBIT,RECHARGE,SMS,OUTGOING,INCOMING Name1,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,1,,,1,,,,,,,,,,,,,,,,,,,,, Name2,,,,1,,1,,,,,,,,,,,,,,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, Name3,1,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,,,,,,,,,,,,,,,,,,,1,,, Note: Please revisit your expected output. It has few mistakes in it as you can see from the output generated from the script above.
Here is an attempt at solving this using awk: Content of script.awk BEGIN { FS = OFS = "," } function combinations(flds, itr, i, pre) { for (i=++cnt; i<=numRecs; i++) { ++n sep = "" for (pre=1; pre<=itr; pre++) { newRecs[n] = newRecs[n] sep (sprintf ("%s", flds[pre])); sep = "-" } newRecs[n] = newRecs[n] sep (sprintf ("%s", flds[i])) ; } } NR==1 { for (fld=3; fld<NF; fld++) { recs[++numRecs] = $fld } for (iter=0; iter<numRecs; iter++) { combinations(recs, iter) } next } !seen[$2]++ { desc[++d] = $2 } { y = 0; var = sep = "" for (idx=3; idx<NF; idx++) { if ($idx == "TRUE") { is_true[++y] = recs[idx-2] } } for (z=1; z<=y; z++) { var = var sep sprintf ("%s", is_true[z]) sep = "-" } data[$2,var]++; } END{ printf "%s," , "Desc" for (k=1; k<=n; k++) { printf "%s%s", newRecs[k],(k==n?RS:FS) } for (name=1; name<=d; name++) { printf "%s,", desc[name]; for (nR=1; nR<=n; nR++) { printf "%s%s", (data[desc[name],newRecs[nR]]?data[desc[name],newRecs[nR]]:""), (nR==n?RS:FS) } } } Sample file Locationx,Desc,A,B,C,Locationy ab123,Name1,TRUE,TRUE,TRUE,ab1234 ab123,Name2,TRUE,FALSE,TRUE,ab1234 ab123,Name2,FALSE,FALSE,TRUE,ab1234 ab123,Name1,TRUE,TRUE,TRUE,ab1234 ab123,Name2,TRUE,TRUE,TRUE,ab1234 ab123,Name3,FALSE,FALSE,FALSE,ab1234 ab123,Name3,TRUE,FALSE,FALSE,ab1234 ab123,Name3,TRUE,TRUE,FALSE,ab1234 ab123,Name3,TRUE,TRUE,FALSE,ab1234 ab123,Name1,TRUE,TRUE,FALSE,ab1234 Execution: $ awk -f script.awk file Desc,A,B,C,A-B,A-C,A-B-C Name1,,,,1,,2 Name2,,,1,,1,1 Name3,1,,,2,, Now, there is pretty evident bug in the combination function. It does not recurse to print all combinations. For eg: for A B C D it will print A B C AB AC ABC but not BC
Use of uninitialized value in concatenation (.) or string at or string at
I've this error: Use of uninitialized value $index in concatenation (.) or string at getdesc.pl line 43, <OctetsIn> line 2. part of my code as follows: my $select_sth = $dbh->prepare("SELECT Hid,Hostname,IP FROM Devices") or die "$dbh->errstr"; $select_sth->execute() or die "$dbh->errstr"; while ( my $row_ref = $select_sth->fetchrow_hashref ) { my $hostname = $row_ref->{'Hostname'}; if ( $hostname ne 'null' ) { my $hid = $row_ref->{'Hid'}; my $ip = $row_ref->{'IP'}; my $desc = "null"; my $index = 0; open( OctetsIn, "snmpwalk -v2c -c public $ip 1.3.6.1.2.1.18 |" ) or die "can't exec: $!"; while (<OctetsIn>) { chomp; print <OctetsIn> . "\n"; /IF-MIB::ifAlias.(\S+) = STRING: (\S+)/; $index = $1; $desc = $2; $dbh->do( "INSERT INTO Description (Hid,index,desc) Values ($hid,$index,'$desc')" ) or die "$dbh->errstr"; } } } close(OctetsIn); What error is there in my code? anyone knows how to fix the error ? The error is on the line: $dbh->do("INSERT INTO Description (Hid,index,desc) Values ($hid,$index,'$desc')") or die "$dbh->errstr";
You should test if regex was successful prior to assigning $1 to $index, ie. # skip to next line if current did not match, as $1 and $2 are undefined /IF-MIB::ifAlias.(\S+) = STRING: (\S+)/ or next;
There are three issues regarding your innermost while loop: You're reading from the filehandle twice when trying to just print the current line: while (<OctetsIn>) { chomp; print <OctetsIn> . "\n"; # Should be: print "$_\n"; Always verify that your regular expression matched before using capture variables. /IF-MIB::ifAlias.(\S+) = STRING: (\S+)/; $index = $1; # Will be undefined if regex doesn't match $desc = $2; Use placeholders and bind values instead of manually including values in a SQL statement: Should aim to never interpolate values directly into a SQL statement like below: "INSERT INTO Description (Hid,index,desc) Values ($hid,$index,'$desc')" To clean up these three issues, I'd transform your inner while loop to something like the following. while (<OctetsIn>) { chomp; print "$_\n"; if (my ($index, $desc) = /IF-MIB::ifAlias.(\S+) = STRING: (\S+)/) { $dbh->do( "INSERT INTO Description (Hid,index,desc) Values (?,?,?)", undef, $hid, $index, $desc ) or die $dbh->errstr; } }
$index = $1; your regexp doesn't match, so $1 is undef
Sort associative array with AWK
Here's my array (gawk script) : myArray["peter"] = 32 myArray["bob"] = 5 myArray["john"] = 463 myArray["jack"] = 11 After sort, I need the following result : bob 5 jack 11 peter 32 john 463 When i use "asort", indices are lost. How to sort by array value without losing indices ? (I need ordered indices based on their values) (I need to obtain this result with awk/gawk only, not shell script, perl, etc) If my post isn't clear enough, here is an other post explaining the same issue : http://www.experts-exchange.com/Programming/Languages/Scripting/Shell/Q_26626841.html ) Thanks in advance Update : Thanks to you both, but i need to sort by values, not indices (i want ordered indices according to their values). In other terms, i need this result : bob 5 jack 11 peter 32 john 463 not : bob 5 jack 11 john 463 peter 32 (I agree, my example is confusing, the chosen values are pretty bad) From the code of Catcall, I wrote a quick implementation that works, but it's rather ugly (I concatenate keys & values before sort and split during comparison). Here's what it looks like : function qsort(A, left, right, i, last) { if (left >= right) return swap(A, left, left+int((right-left+1)*rand())) last = left for (i = left+1; i <= right; i++) if (getPart(A[i], "value") < getPart(A[left], "value")) swap(A, ++last, i) swap(A, left, last) qsort(A, left, last-1) qsort(A, last+1, right) } function swap(A, i, j, t) { t = A[i]; A[i] = A[j]; A[j] = t } function getPart(str, part) { if (part == "key") return substr(str, 1, index(str, "#")-1) if (part == "value") return substr(str, index(str, "#")+1, length(str))+0 return } BEGIN { } { } END { myArray["peter"] = 32 myArray["bob"] = 5 myArray["john"] = 463 myArray["jack"] = 11 for (key in myArray) sortvalues[j++] = key "#" myArray[key] qsort(sortvalues, 0, length(myArray)); for (i = 1; i <= length(myArray); i++) print getPart(sortvalues[i], "key"), getPart(sortvalues[i], "value") } Of course I'm interested if you have something more clean... Thanks for your time
Edit: Sort by values Oh! To sort the values, it's a bit of a kludge, but you can create a temporary array using a concatenation of the values and the indices of the original array as indices in the new array. Then you can asorti() the temporary array and split the concatenated values back into indices and values. If you can't follow that convoluted description, the code is much easier to understand. It's also very short. # right justify the integers into space-padded strings and cat the index # to create the new index for (i in myArray) tmpidx[sprintf("%12s", myArray[i]),i] = i num = asorti(tmpidx) j = 0 for (i=1; i<=num; i++) { split(tmpidx[i], tmp, SUBSEP) indices[++j] = tmp[2] # tmp[2] is the name } for (i=1; i<=num; i++) print indices[i], myArray[indices[i]] Edit 2: If you have GAWK 4, you can traverse the array by order of values without performing an explicit sort: #!/usr/bin/awk -f BEGIN { myArray["peter"] = 32 myArray["bob"] = 5 myArray["john"] = 463 myArray["jack"] = 11 PROCINFO["sorted_in"] = "#val_num_asc" for (i in myArray) { {print i, myArray[i]}} } } There are settings for traversing by index or value, ascending or descending and other options. You can also specify a custom function. Previous answer: Sort by indices If you have an AWK, such as gawk 3.1.2 or greater, which supports asorti(): #!/usr/bin/awk -f BEGIN { myArray["peter"] = 32 myArray["bob"] = 5 myArray["john"] = 463 myArray["jack"] = 11 num = asorti(myArray, indices) for (i=1; i<=num; i++) print indices[i], myArray[indices[i]] } If you don't have asorti(): #!/usr/bin/awk -f BEGIN { myArray["peter"] = 32 myArray["bob"] = 5 myArray["john"] = 463 myArray["jack"] = 11 for (i in myArray) indices[++j] = i num = asort(indices) for (i=1; i<=num; i++) print i, indices[i], myArray[indices[i]] }
Use the Unix sort command with the pipe, keeps Awk code simple and follow Unix philosophy Create a input file with values seperated by comma peter,32 jack,11 john,463 bob,5 Create a sort.awk file with the code BEGIN { FS=","; } { myArray[$1]=$2; } END { for (name in myArray) printf ("%s,%d\n", name, myArray[name]) | "sort -t, -k2 -n" } Run the program, should give you the output $ awk -f sort.awk data bob,5 jack,11 peter,32 john,463
PROCINFO["sorted_in"] = "#val_num_desc"; Before iterating an array, use the above statement. But, it works in awk version 4.0.1. It does not work in awk version 3.1.7. I am not sure in which intermediate version, it got introduced.
And the simple answer... function sort_by_myArray(i1, v1, i2, v2) { return myArray[i2] < myArray[i1]; } BEGIN { myArray["peter"] = 32; myArray["bob"] = 5; myArray["john"] = 463; myArray["jack"] = 11; len = length(myArray); asorti(myArray, k, "sort_by_myArray"); # Print result. for(n = 1; n <= len; ++n) { print k[n], myArray[k[n]] } }
Use asorti: #!/usr/bin/env -S gawk -f { score[$1] = $0; array[sprintf("%3s",$2) $1] = $1; } END { asorti(array, b) for(i in b) { name = array[b[i]] print score[name] } }
The following function works in Gawk 3.1.7 and doesn't resort to any of the workarounds described above (no external sort command, no array subscripts, etc.) It's just a basic implementation of the insertion sort algorithm adapted for associative arrays. You pass it an associative array to sort on the values and an empty array to populate with the corresponding keys. myArray["peter"] = 32; myArray["bob"] = 5; myArray["john"] = 463; myArray["jack"] = 11; len = resort( myArray, result ); for( i = 1; i <= len; i++ ) { key = result[ i ]; print i ": " key " = " myArray[ key ]; } Here is the implementation: function resort( data, list, key, len, i, j, v ) { len = 0; for( key in data ) { list[ ++len ] = key; } # insertion sort algorithm adapted for # one-based associative arrays in gawk for( i = 2; i <= len; i++ ) { v = list[ i ]; for( j = i - 1; j >= 1; j-- ) { if( data[ list[ j ] ] <= data[ v ] ) break; list[ j + 1 ] = list[ j ]; } list[ j + 1 ] = v; } return len; } You can "reverse sort" by simply iterating the resulting array in descending order.