sort

31 views
Skip to first unread message

Norman R. Frech CPLS

unread,
Aug 21, 1990, 4:20:05 PM8/21/90
to
Due to great stupidity I lost my one of my programs which contained an
sort of an array of integers. Naturally, I need the logic and my sort
is sorting on the character string representations. I tried the
subroutine in the perl.man with no success. Would someone please
send me the logic for a numeric sort of an array. Thanks...

Norm Frech <fr...@mwraaa.army.mil>

Randal Schwartz

unread,
Aug 21, 1990, 6:43:27 PM8/21/90
to

sub by_the_numbers {
$a - $b;
}

@a = (3,5,7,9,11,13,15,16,14,12,10,8,6,4,2);

@sorta = sort by_the_numbers @a;

print "@sorta\n";

How's that?

print "Just another Perl (book) hacker,"
--
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III |
| mer...@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

Andrew Vignaux

unread,
Aug 22, 1990, 7:10:18 AM8/22/90
to
In article <1990Aug21.2...@iwarp.intel.com>,

mer...@iwarp.intel.com (Randal Schwartz) writes:
>sub by_the_numbers {
> $a - $b;
>}

The original poster asked about sorting integers so this answer is
right. However, there is a possible trap. I couldn't work out why

@a = (50.1, 50.4, 50.2);


@sorta = sort by_the_numbers @a;
print "@sorta\n";

sometimes didn't work for me (well actually, imagine a LARGE list with
a few |element1 - element2| < 0.5)

"sort" wants integers (<, ==, >) 0 not reals!

Is there a better/stronger/faster "float" comparison function than

sub by_the_numbers { $a > $b ? 1 : $a < $b ? -1 : 0; }

especially if $a and $b are indexes into an associative array?
e.g ... $foo{$a} > $foo{$b} ? ...


Here's an interesting sorter (extracted so my one-liner fits ;-) I
think you can tell that perl is using qsort "as time goes by".

$s=(localtime(time))[0]; sub n { ($a - $b) * $s; }

print grep(s/.*\t//,sort n grep($_=++$i/-50."\t$_",split(/\n*/,<<JAPH)));
,rekcah lreP rehtona tsuJ
JAPH

Andrew
--
Domain address: Andrew....@comp.vuw.ac.nz
Lament: Why do my one-liners never fit in one line? :-(

Randal Schwartz

unread,
Aug 22, 1990, 12:04:17 PM8/22/90
to
In article <1990Aug22....@comp.vuw.ac.nz>, Andrew.Vignaux@comp (Andrew Vignaux) writes:
| $s=(localtime(time))[0]; sub n { ($a - $b) * $s; }
|
| print grep(s/.*\t//,sort n grep($_=++$i/-50."\t$_",split(/\n*/,<<JAPH)));
| ,rekcah lreP rehtona tsuJ
| JAPH

Wow! A piece of code that really *does* fail based on time-of-day!
(And in Perl... I'm heartbroken. :-)

| Lament: Why do my one-liners never fit in one line? :-(

You don't use long enough lines. :-)

P.S. If you don't see it, think about what happens at 0 seconds into
the minute.

print "Just another Perl [book] hacker,"

Mike McManus

unread,
Aug 28, 1990, 11:52:52 AM8/28/90
to
In article <1990Aug22....@comp.vuw.ac.nz> Andrew....@comp.vuw.ac.nz (Andrew Vignaux) writes:
>
> In article <1990Aug21.2...@iwarp.intel.com>,
> mer...@iwarp.intel.com (Randal Schwartz) writes:
> >sub by_the_numbers {
> > $a - $b;
> >}
>
> The original poster asked about sorting integers so this answer is
> right.
...

> Is there a better/stronger/faster "float" comparison function than
>
> sub by_the_numbers { $a > $b ? 1 : $a < $b ? -1 : 0; }
>
> especially if $a and $b are indexes into an associative array?
> e.g ... $foo{$a} > $foo{$b} ? ...

Interestingly enuff, I had need for a similar sorting routine today, but with a
twist: I want to sort the indices of an associative array that are of the form
"A0, A1, A2, ..., A9, A10, ..." Of course an alphabetic sort returns "A0, A10,
A11, A19, ..., A1, ...", not what I want!

Any simple solutions? Thanks!
--
Disclaimer: All spelling and/or grammar in this document are guaranteed to be
correct; any exseptions is the is wurk uv intter-net deemuns,.

Mike McManus Mike.M...@FtCollins.NCR.COM, or
NCR Microelectronics ncr-mpd!mik...@ncr-sd.sandiego.ncr.com, or
2001 Danfield Ct. uunet!ncrlnk!ncr-mpd!garage!mikemc
Ft. Collins, Colorado
(303) 223-5100 Ext. 378

Randal Schwartz

unread,
Aug 29, 1990, 2:36:39 AM8/29/90
to
In article <MIKE.MCMANUS....@mustang.FtCollins.NCR.com>, Mike.McManus@FtCollins (Mike McManus) writes:
| Interestingly enuff, I had need for a similar sorting routine today, but with a
| twist: I want to sort the indices of an associative array that are of the form
| "A0, A1, A2, ..., A9, A10, ..." Of course an alphabetic sort returns "A0, A10,
| A11, A19, ..., A1, ...", not what I want!
|
| Any simple solutions? Thanks!

Well, two come to mind. The first one is pretty trivial source code:

sub by_the_numbers_mostly { substr($a,1,999) > substr($b,1,999) ? 1 : -1; }

However, I haven't tested this for speed (it's doing a lot of work in
those substr's over and over and over again). What you might want to
do is build a parallel array:

@foo=('A10'..'A19','A0'..'A9'); # not in order, for demo

grep(s/^.//,@fookey = @foo);

sub byfookey { $fookey[$a] > $fookey[$b] ? 1 : -1; }

@sortfoo = @foo[sort byfookey $[..$#foo];

print "@sortfoo";

For large arrays, I believe this would win. For small arrays, the
first would probably win (I haven't tested that... if someone has a
few more minutes than me, go ahead and please let us know).

print "Just another Perl hacker,"

Tom Christiansen

unread,
Aug 28, 1990, 10:00:50 PM8/28/90
to
In article <MIKE.MCMANUS....@mustang.FtCollins.NCR.com> Mike.M...@FtCollins.NCR.com (Mike McManus) writes:
>Interestingly enuff, I had need for a similar sorting routine today, but with a
>twist: I want to sort the indices of an associative array that are of the form
>"A0, A1, A2, ..., A9, A10, ..." Of course an alphabetic sort returns "A0, A10,
>A11, A19, ..., A1, ...", not what I want!
>
>Any simple solutions? Thanks!

Is this simple enough for the sort function?

sub bynum { substr($a,$[+1,10) > substr($b,$[+1,10); }

--tom
--
"UNIX was never designed to keep people from doing stupid things, because
that policy would also keep them from doing clever things." [Doug Gwyn]

Randal Schwartz

unread,
Aug 29, 1990, 3:14:54 PM8/29/90
to
In article <105...@convex.convex.com>, tchrist@convex (Tom Christiansen) writes:
| Is this simple enough for the sort function?
|
| sub bynum { substr($a,$[+1,10) > substr($b,$[+1,10); }

Nope nope nope. I made that same mistake once. Think about
what this returns... either "1" or "0", not "1" or "-1". Arrrgh. :-)

You want something like I already posted involving a test and a 1 or
-1 return.

print pack("c*",(32..127)[42,85,83,84,0,65,78,79,84,72,69,82,0,48,69,82,76,0,72,65,67,75,69,82,12])

Larry Wall

unread,
Aug 29, 1990, 8:24:44 PM8/29/90
to
In article <1990Aug29.1...@iwarp.intel.com> mer...@iwarp.intel.com (Randal Schwartz) writes:

: In article <105...@convex.convex.com>, tchrist@convex (Tom Christiansen) writes:
: | Is this simple enough for the sort function?
: |
: | sub bynum { substr($a,$[+1,10) > substr($b,$[+1,10); }
:
: Nope nope nope. I made that same mistake once. Think about
: what this returns... either "1" or "0", not "1" or "-1". Arrrgh. :-)
:
: You want something like I already posted involving a test and a 1 or
: -1 return.

I just had the weirdest thought. The ne and != operators should maybe
return -1 or +1 when the operands aren't equal.

Larry

Randal Schwartz

unread,
Aug 30, 1990, 3:50:25 AM8/30/90
to
In article <93...@jpl-devvax.JPL.NASA.GOV>, lwall@jpl-devvax (Larry Wall) writes:
| I just had the weirdest thought. The ne and != operators should maybe
| return -1 or +1 when the operands aren't equal.

And when Larry has weird thoughts, *I* get to write them down. :-)
Yeah. >>patch29, right? Along with -A, -C, -M filetests and "DATA"
filehandle. Or did you not announce that yet? Oops... too late. :-)

print "Just another Perl [book] hacker,"

Andrew Vignaux

unread,
Aug 31, 1990, 8:17:41 PM8/31/90
to
In article <1990Aug29.1...@iwarp.intel.com>
mer...@iwarp.intel.com (Randal Schwartz) writes:
: In article <105...@convex.convex.com>, tchrist@convex (Tom
Christiansen) writes:
: | Is this simple enough for the sort function?
: |
: | sub bynum { substr($a,$[+1,10) > substr($b,$[+1,10); }
:
: Nope nope nope. I made that same mistake once. Think about
: what this returns... either "1" or "0", not "1" or "-1". Arrrgh. :-)

Actually, the Berkeley qsort (well let's be precise -- the qsort on
our MORE/bsd 4.3+ boxes running on hp300s) still manages to sort if
you use this comparison routine!

In article <93...@jpl-devvax.JPL.NASA.GOV>, lw...@jpl-devvax.JPL.NASA.GOV


(Larry Wall) writes:
> I just had the weirdest thought. The ne and != operators should maybe
> return -1 or +1 when the operands aren't equal.
>
> Larry

This is a great idea! In conjunction with || returning the last value
evaluated means sort functions can turn into:

sub sort_it { $key1{$a} ne $key1{$b} || -(&fun2{$a} != &fun2{$b}); }

where &fun2() can return floats!

Unfortunately, it will break some of my scripts. E.g

if (($sort_rank != 0) + ($sort_articles != 0) + ($sort_size != 0) > 1) {
print STDERR "$program: only one of -r, -a, -s should be supplied\n";
exit (1);
}

where $sort_* could be -1, 0, +1. But I can fix those.

Possible problems:
+ it looks strange. Take another look at sort_it! Does it sort
things the right way?

+ people will have to re-think how to use comparison operators
because "!=" does not mean "!( == )" E.g negating an
expression (ala De Morgan) will take some thought

+ -(a != b) <=> (-a != -b) which is new!

+ it'll screw up my C programming :-)

I realise it isn't a democracy, but you've got my vote.

Johan Vromans

unread,
Sep 1, 1990, 5:57:42 AM9/1/90
to
> I just had the weirdest thought. The ne and != operators should maybe
> return -1 or +1 when the operands aren't equal.

Please don't. It will break lots of existing scripts. Moreover, perl
is already wierd enough. I can imagine lots of perl novice users
shifting back to grep/sed/nawk once they discover that != is not the
same anymore as ! == .

I hesitate to say so, but I think this deserves a new built-in
fuction, e.g 'order($a,$b)' and 'lexorder($a,$b)'. The latter can also
take internationalization issues into account, so you can have quick
and dirty string comparisons using eq ne gt ge le lt, and formal
correct (hence a bit slower) using lexorder.

Johan
--
Johan Vromans j...@mh.nl via internet backbones
Multihouse Automatisering bv uucp: ..!{uunet,hp4nl}!mh.nl!jv
Doesburgweg 7, 2803 PL Gouda, The Netherlands phone/fax: +31 1820 62911/62500
------------------------ "Arms are made for hugging" -------------------------

Brandon S. Allbery KB8JRR/KT

unread,
Sep 1, 1990, 10:37:25 AM9/1/90
to
As quoted from <93...@jpl-devvax.JPL.NASA.GOV> by lw...@jpl-devvax.JPL.NASA.GOV (Larry Wall):
+---------------
+---------------

Not necessary. One change should do it (untested, I have neither the space
nor the time to bring up Perl on ncoast):

sub bynum { substr($a,$[+1,10) - substr($b,$[+1,10); }

The -1/+1 idea is interesting, however. (Another doohickey for the Swiss Army
Chainsaw? ;-)

++Brandon
--
Me: Brandon S. Allbery VHF/UHF: KB8JRR/KT on 220, 2m, 440
Internet: all...@NCoast.ORG Delphi: ALLBERY
uunet!usenet.ins.cwru.edu!ncoast!allbery America OnLine: KB8JRR

Felix Lee

unread,
Sep 1, 1990, 2:50:43 PM9/1/90
to
>I just had the weirdest thought. The ne and != operators should maybe
>return -1 or +1 when the operands aren't equal.

Call it something else, like "cmp" and "<=>" and I'll take it. I've
had vague yearnings for a comparison operator for a long time.
--
Felix Lee fl...@cs.psu.edu

Larry Wall

unread,
Sep 1, 1990, 6:16:50 PM9/1/90
to
In article <Fra5m=?1...@cs.psu.edu> fl...@guardian.cs.psu.edu (Felix Lee) writes:
: >I just had the weirdest thought. The ne and != operators should maybe

: >return -1 or +1 when the operands aren't equal.
:
: Call it something else, like "cmp" and "<=>" and I'll take it. I've
: had vague yearnings for a comparison operator for a long time.

I like those, much though I loathe 3-character operators. They feel right
and are easy to remember.

While we're redesigning the language, I've been considering another problem.
Subroutines right now have no way to determine what package they were
called from, which makes it difficult to install variables into the correct
package. In addition, the debugger needs to know the file and line number
a routine was called from. I propose a function "caller", which does this:

($package, $file, $line) = caller;

This would be easy to implement--I already keep a pointer to the current
statement, and the current statement contains this info. It would merely
entail making the saved current statement pointer available to the
subroutine.

Other items sneaking in at the last moment. Filetests -M, -A and -C will
return the file's age in days (possibly fractional) at the time the script
started. This will make it much easier to write middle-of-the-night
skulkers.

The tr/// function now has modifier c, d and s. c complements the searchlist,
d deletes any characters in searchlist WITHOUT a replacement in replacementlist,
and s squashes multiple contiguous occurrences of replacementlist characters
to one occurence.

Chip Salzenberg sent me a complete patch to add System V IPC (msg, sem and
shm calls), so I added them. If that bothers you, you can always undefine
them in config.sh. :-)

Lessee... Oh yeah. There's a scalar() pseudo-function call that merely
supplies a scalar context in the middle of a list. I know you can do it
by saying OP . "", but it's better documentation and more efficient. So
you can say things like

local($nextline) = scalar(<STDIN>);

I don't see a need for an operator to supply an array context.

I'm also supplying sysread and syswrite as direct hooks to the read
and write system calls, for those times when you just have to get past
standard I/O.

Some of these aren't even implemented yet, but I know I can get them done
by the time the book comes out... :-)

Holler quick if any of this seems like a tragic mistake. I already listened
to you on <=> and cmp. I'm not unreasonable *all* the time.

Larry

Jan Dj{rv

unread,
Sep 2, 1990, 9:23:29 AM9/2/90
to
Larry Wall writes:

> I just had the weirdest thought. The ne and != operators should maybe
> return -1 or +1 when the operands aren't equal.
>

No, no, please don't do that. It would be very confusing if != and
! == didn't mean the same thing. It would probably break old programs as well.

Besides, such a feature would only be useful in sort sub's (right ?) and
it isn't that hard to write them correctly.

Jan D.

Dale Worley

unread,
Sep 4, 1990, 12:06:12 PM9/4/90
to

X-Name: Felix Lee

Call it something else, like "cmp" and "<=>" and I'll take it. I've
had vague yearnings for a comparison operator for a long time.

Yeah, that'd be both neat and useful.

Dale Worley Compass, Inc. wor...@compass.com
--
I try to make everyone's day a little more surreal.

Scott Schwartz

unread,
Sep 4, 1990, 3:47:36 PM9/4/90
to

Dale Worley writes:

Call it something else, like "cmp" and "<=>" and I'll take it. I've
had vague yearnings for a comparison operator for a long time.

Yeah, that'd be both neat and useful.


I sent a note to Larry suggesting this, but here it is again...
Why not "@" for cmp? i.e.

$a @ $b

asks where $a is at in relation to $b. Because the @ is whitespace
delimited and is looking for strings, it doesn't clash with the @array
token.

Tom Neff

unread,
Sep 4, 1990, 6:34:28 AM9/4/90
to
In article <93...@jpl-devvax.JPL.NASA.GOV> lw...@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
>Other items sneaking in at the last moment. Filetests -M, -A and -C will
>return the file's age in days (possibly fractional) at the time the script
>started. This will make it much easier to write middle-of-the-night
>skulkers.

Why when the script started? Why not their age NOW? That way you could
not only write middle-of-the-night skulkers, but usable Perl daemons to
check for things at intervals.

If the objection is to repeated time() calls, I suggest the tradeoff is
well worth it.

If the objection is nonetheless sustained, how about making the "$NOW"
variable used by -[MAC] modifiable by the programmer.

--
"Just the fax, ma'am." o..oo Tom Neff
-- John McClane .oo.. tn...@bfmny0.BFM.COM

Tom Christiansen

unread,
Sep 5, 1990, 5:36:06 PM9/5/90
to
>Other items sneaking in at the last moment. Filetests -M, -A and -C will
>return the file's age in days (possibly fractional) at the time the script
>started. This will make it much easier to write middle-of-the-night
>skulkers.

The "at the time of the script" part bothers me a bit; I'd MUCH rather it
were their "instantaneous" age.

When I first saw those operators, I expected them to return a time I could
pass to &ctime(), but instead they give me age. If I want the real time,
I guess I could use (stat(FILE))[9] for mtime and so on. Certainly these
could be easily implemented as subroutines; I'd venture to guess, Larry,
that you consider them common enough operations to make them builtins.

Speaking of such things, I've found myself writing code like this:

if ((stat($tmp))[9] <= (stat($orig))[9]) {

And wishing I could use something like this instead

if ($tmp -nt $orig)

where "-nt" is a binary operator that returns whether the
first operand (either a FILE or a $file) is younger than
the second.

The Korn shell has these three interesting built-in tests:

file1 -nt file2
True if file1 exists and is newer than file2.
file1 -ot file2
True if file1 exists and is older than file2.
file1 -ef file2
True if file1 and file2 exist and refer to the same file.

I would guess the first two compare mtimes and the last
one compares (dev,ino) pairs.

At least the first two seem common enough to be operators.

Matthias Urlichs

unread,
Sep 5, 1990, 6:28:24 PM9/5/90
to
In comp.lang.perl, article <15...@bfmny0.BFM.COM>,

tn...@bfmny0.BFM.COM (Tom Neff) writes:
< In article <93...@jpl-devvax.JPL.NASA.GOV> lw...@jpl-devvax.JPL.NASA.GOV (Larry Wall) writes:
< >Other items sneaking in at the last moment. Filetests -M, -A and -C will
< >return the file's age in days (possibly fractional) at the time the script
< >started. This will make it much easier to write middle-of-the-night
< >skulkers.
<
< Why when the script started? Why not their age NOW? That way you could
< not only write middle-of-the-night skulkers, but usable Perl daemons to
< check for things at intervals.
<
On the other hand, other useable Perl daemons might get started once a
day/night/week, and may do some lengthy tasks (like analyzing log files, which
is kind of what Perl seems to be meant for originally (other than writing an
RN replacement of course ;-) )) before looking at the date of the next file.
In that case, the script will presumably be started at the same time every
[interval] and testing the age of files will not leave any "windows" which
could conceivably skew the statistics.

Anyway, it's trivial to convert between one way and the other via the time
function and a division by 24*60*60...

< If the objection is nonetheless sustained, how about making the "$NOW"
< variable used by -[MAC] modifiable by the programmer.
<

...or by saying "$NOW = time", of course, if Larry decides to implement it
that way.
--
Matthias Urlichs -- url...@smurf.sub.org -- url...@smurf.ira.uka.de
Humboldtstrasse 7 - 7500 Karlsruhe 1 - FRG -- +49+721+621127(Voice)/621227(PEP)

Reply all
Reply to author
Forward
0 new messages