[17817] in Perl-Users-Digest

home help back first fref pref prev next nref lref last post

Perl-Users Digest, Issue: 5237 Volume: 9

daemon@ATHENA.MIT.EDU (Perl-Users Digest)
Thu Jan 4 18:56:32 2001

Date: Thu, 4 Jan 2001 15:56:14 -0800 (PST)
From: Perl-Users Digest <Perl-Users-Request@ruby.OCE.ORST.EDU>
To: Perl-Users@ruby.OCE.ORST.EDU (Perl-Users Digest)
Message-Id: <978652574-v9-i5237@ruby.oce.orst.edu>
Content-Type: text

Perl-Users Digest           Thu, 4 Jan 2001     Volume: 9 Number: 5237

Today's topics:
        Numeric comparison fails on numbers? (Steven Smolinski)
    Re: Numeric comparison fails on numbers? (Tad McClellan)
    Re: Numeric comparison fails on numbers? (Tad McClellan)
    Re: Numeric comparison fails on numbers? (Steven Smolinski)
    Re: Numeric comparison fails on numbers? <tony_curtis32@yahoo.com>
    Re: Numeric comparison fails on numbers? (Steven Smolinski)
    Re: Numeric comparison fails on numbers? (Garry Williams)
    Re: Numeric comparison fails on numbers? (Abigail)
    Re: Numeric comparison fails on numbers? (Tad McClellan)
    Re: Numeric comparison fails on numbers? (Anno Siegel)
    Re: Numeric comparison fails on numbers? Gordon.Haverland@agric.gov.ab.ca
    Re: Numeric comparison fails on numbers? (Abigail)
        O.T. (--index--)
        Odd sorting behavior... <kaptainkory@yahoo.com>
    Re: Odd sorting behavior... (Martien Verbruggen)
    Re: Odd sorting behavior... <iltzu@sci.invalid>
    Re: Odd sorting behavior... <kaptainkory@yahoo.com>
    Re: Odd sorting behavior... (Martien Verbruggen)
    Re: Odd sorting behavior... (Martien Verbruggen)
    Re: Odd sorting behavior... <kaptainkory@yahoo.com>
    Re: Odd sorting behavior... <uri@sysarch.com>
    Re: Odd sorting behavior... (Abigail)
    Re: Odd sorting behavior... (Martien Verbruggen)
        Digest Administrivia (Last modified: 16 Sep 99) (Perl-Users-Digest Admin)

----------------------------------------------------------------------

Date: Fri, 29 Dec 2000 23:21:15 GMT
From: sjs@linux.ca (Steven Smolinski)
Subject: Numeric comparison fails on numbers?
Message-Id: <slrn94qb09.11n.sjs@ragnar.stevens.gulch>

I'm trying to wrap my brain around how perl DWIMs scalars from strings
to numbers.  For instance, if I add up a few stringified numbers, and
then compare them against a number, should I use a numerical
comparison? 

The small program below shows my confusion:

#!/usr/bin/perl -w
use strict;

my @values = ( '0.1', '0.7', '0.5', '0.7' );  # strings, right?
my $sum = 0;

$sum += +$_ for @values;  # the unary + is to try and keep it numeric
                          # but it doesn't make a difference in output

# numerical comparison test
if ( $sum != 2 ) {
    print "sum ($sum) is not 2 with numerical comparison.\n";
} 
else {
    print "sum ($sum) is 2 with numerical comparison\n";
}

# stringwise comparison test
if ( $sum ne 2 ) {
    print "sum ($sum) is not 2 with stringwise comparison.\n";
} 
else {
    print "sum ($sum) is 2 with stringwise comparison\n";
}
__END__

stevens@ragnar:~/src/perl > ./compare
sum (2) is not 2 with numerical comparison.
sum (2) is 2 with stringwise comparison
stevens@ragnar:~/src/perl >

I've tried comparing against 2.0 instead, with identical results.
I've also tried it on 5.005_3 and 5.6.0 with the same results. 
Any help appreciated.  TIA.

Steve
-- 
Steven Smolinski => http://www.steven.cx/


------------------------------

Date: Fri, 29 Dec 2000 16:54:04 -0500
From: tadmc@metronet.com (Tad McClellan)
Subject: Re: Numeric comparison fails on numbers?
Message-Id: <slrn94q1vs.23c.tadmc@magna.metronet.com>

Steven Smolinski <sjs@linux.ca> wrote:

>I'm trying to wrap my brain around how perl DWIMs scalars from strings
>to numbers.  


Your confusion does not come from the conversion between strings
and numbers. You're looking in the wrong place.

Your problem is discussed in the Perl FAQ, part 4:

   "Why am I getting long decimals (eg, 19.9499999999999) 
    instead of the numbers I should be getting (eg, 19.95)?"


>For instance, if I add up a few stringified numbers, and
>then compare them against a number, should I use a numerical
>comparison? 


If you want them compared as numbers, then yes, use the
numerical comparison operator.

Your problem is doing a test for (in)equality on a floating point number.


>The small program below shows my confusion:
>
>#!/usr/bin/perl -w
>use strict;
>
>my @values = ( '0.1', '0.7', '0.5', '0.7' );  # strings, right?
>my $sum = 0;
>
>$sum += +$_ for @values;  # the unary + is to try and keep it numeric
                                                       ^^^^^^^^^^^^^^^

The += already forces its operands to numeric, the unary + is superfluous.


>                          # but it doesn't make a difference in output
>
># numerical comparison test


Add a debug statement right about here, and all will become clear:

   printf "%30.20f\n", $sum;


>if ( $sum != 2 ) {
           ^^
           ^^

"equal" means *exactly* equal, up to the precision supported
by your platform.


># stringwise comparison test
>if ( $sum ne 2 ) {
           ^^^^

You should be comparing strings if you use the string comparison operator:

   if ( $sum ne '2' ) {


>I've tried comparing against 2.0 instead, with identical results.


It will work fine if you avoid floating point arithmetic.

   my @values = ( '01', '07', '05', '07' );

And testing for twenty, works like you expect.


-- 
    Tad McClellan                          SGML consulting
    tadmc@metronet.com                     Perl programming
    Fort Worth, Texas


------------------------------

Date: Fri, 29 Dec 2000 17:07:40 -0500
From: tadmc@metronet.com (Tad McClellan)
Subject: Re: Numeric comparison fails on numbers?
Message-Id: <slrn94q2pc.26g.tadmc@magna.metronet.com>

I myself <tadmc@metronet.com> wrote:
>Steven Smolinski <sjs@linux.ca> wrote:
>
>>I'm trying to wrap my brain around how perl DWIMs scalars from strings
>>to numbers.  
>
>
>Your confusion does not come from the conversion between strings
>and numbers. You're looking in the wrong place.

>>my @values = ( '0.1', '0.7', '0.5', '0.7' );  # strings, right?
                                                  ^^^^^^^

Also wanted to point out that you get the same behavior when
they are NOT strings:

   my @values = ( 0.1, 0.7, 0.5, 0.7 );


-- 
    Tad McClellan                          SGML consulting
    tadmc@metronet.com                     Perl programming
    Fort Worth, Texas


------------------------------

Date: Sat, 30 Dec 2000 01:21:33 GMT
From: sjs@linux.ca (Steven Smolinski)
Subject: Re: Numeric comparison fails on numbers?
Message-Id: <slrn94qi1s.18q.sjs@ragnar.stevens.gulch>

Tad <tadmc@metronet.com> wrote:
>Steven Smolinski <sjs@linux.ca> wrote:
>
>>I'm trying to wrap my brain around how perl DWIMs scalars from strings
>>to numbers.  
>
>Your confusion does not come from the conversion between strings
>and numbers. You're looking in the wrong place.

Thanks for the pointer, Tad.  I didn't realize that floating point
accuracy was my problem because my debug prints were of the form:

print $sum, "\n";

These prints 'rounded' the figure, whilst:

printf "%30.20f\n", $sum;

shows the floater in all its glory.  I'll have to remember this.

I've managed to solve my problem by rounding the figure I test to an
appropriate number of significant digits first:

$sum = sprintf "%.1f", $sum;

Then I can test numerically against 2, or 2.0, or whatever.

Thanks again!

Steve
-- 
Steven Smolinski => http://www.steven.cx/


------------------------------

Date: 29 Dec 2000 19:28:37 -0600
From: Tony Curtis <tony_curtis32@yahoo.com>
Subject: Re: Numeric comparison fails on numbers?
Message-Id: <87ofxu8zp6.fsf@limey.hpcc.uh.edu>

>> On Sat, 30 Dec 2000 01:21:33 GMT,
>> sjs@linux.ca (Steven Smolinski) said:

> I've managed to solve my problem by rounding the figure I test to an
> appropriate number of significant digits first:

> $sum = sprintf "%.1f", $sum;

> Then I can test numerically against 2, or 2.0, or whatever.

The usual way is to test the value to see how closely it approaches a
limiting value against a sufficiently small delta:

    my $delta = 0.0001;                 # or however close you want to get
    my $limit = 2.0;                    # in this case

    if (abs($sum - $limit) < $delta) {
      hurrah();
    } else {
      boo();
    }

hth
t
-- 
Eih bennek, eih blavek.


------------------------------

Date: Sat, 30 Dec 2000 01:32:25 GMT
From: sjs@linux.ca (Steven Smolinski)
Subject: Re: Numeric comparison fails on numbers?
Message-Id: <slrn94qiq9.18q.sjs@ragnar.stevens.gulch>

Tony Curtis <tony_curtis32@yahoo.com> wrote:
> >> On Sat, 30 Dec 2000 01:21:33 GMT,
> >> sjs@linux.ca (Steven Smolinski) said:
> 
> > I've managed to solve my problem by rounding the figure I test to an
> > appropriate number of significant digits first:
> 
> > $sum = sprintf "%.1f", $sum;
> 
> > Then I can test numerically against 2, or 2.0, or whatever.
> 
> The usual way is to test the value to see how closely it approaches a
> limiting value against a sufficiently small delta:
> 
>     my $delta = 0.0001;                 # or however close you want to get
>     my $limit = 2.0;                    # in this case
> 
>     if (abs($sum - $limit) < $delta) {
>       hurrah();
>     } else {
>       boo();
>     }

This is great!  Thanks for the algorithm.  I'm going to rewrite it
with this method.

Steve
-- 
Steven Smolinski => http://www.steven.cx/


------------------------------

Date: Sat, 30 Dec 2000 02:56:06 GMT
From: garry@zvolve.com (Garry Williams)
Subject: Re: Numeric comparison fails on numbers?
Message-Id: <a9c36.484$ld.31342@eagle.america.net>

On 29 Dec 2000 19:28:37 -0600, Tony Curtis <tony_curtis32@yahoo.com> wrote:
>>> On Sat, 30 Dec 2000 01:21:33 GMT,
>>> sjs@linux.ca (Steven Smolinski) said:
>
>> I've managed to solve my problem by rounding the figure I test to an
>> appropriate number of significant digits first:
>
>> $sum = sprintf "%.1f", $sum;
>
>> Then I can test numerically against 2, or 2.0, or whatever.
>
>The usual way is to test the value to see how closely it approaches a
>limiting value against a sufficiently small delta:
>
>    my $delta = 0.0001;                 # or however close you want to get
>    my $limit = 2.0;                    # in this case
>
>    if (abs($sum - $limit) < $delta) {
>      hurrah();
>    } else {
>      boo();
>    }

But isn't that the *effect* of rounding to some "appropriate" number
of digits?  

-- 
Garry Williams


------------------------------

Date: 30 Dec 2000 11:12:20 GMT
From: abigail@foad.org (Abigail)
Subject: Re: Numeric comparison fails on numbers?
Message-Id: <slrn94rgok.8df.abigail@tsathoggua.rlyeh.net>

Tad McClellan (tadmc@metronet.com) wrote on MMDCLXXVII September MCMXCIII
in <URL:news:slrn94q1vs.23c.tadmc@magna.metronet.com>:
][ >if ( $sum ne 2 ) {
][            ^^^^
][ 
][ You should be comparing strings if you use the string comparison operator:
][ 
][    if ( $sum ne '2' ) {


Well, no, that's the entire point of Perls automatic conversion. 2 and '2'
are identical. 



Abigail
-- 
perl -MLWP::UserAgent -MHTML::TreeBuilder -MHTML::FormatText -wle'print +(
HTML::FormatText -> new -> format (HTML::TreeBuilder -> new -> parse (
LWP::UserAgent -> new -> request (HTTP::Request -> new ("GET",
"http://work.ucsd.edu:5141/cgi-bin/http_webster?isindex=perl")) -> content))
=~ /(.*\))[-\s]+Addition/s) [0]'


------------------------------

Date: Sat, 30 Dec 2000 07:08:01 -0500
From: tadmc@metronet.com (Tad McClellan)
Subject: Re: Numeric comparison fails on numbers?
Message-Id: <slrn94rk11.36l.tadmc@magna.metronet.com>

Abigail <abigail@foad.org> wrote:
>Tad McClellan (tadmc@metronet.com) wrote on MMDCLXXVII September MCMXCIII
>in <URL:news:slrn94q1vs.23c.tadmc@magna.metronet.com>:
>][ >if ( $sum ne 2 ) {
>][            ^^^^
>][ 
>][ You should be comparing strings if you use the string comparison operator:
>][ 
>][    if ( $sum ne '2' ) {
>
>
>Well, no, that's the entire point of Perls automatic conversion. 2 and '2'
>are identical. 


I knew that of course.

I should have said it better (or correctly even :-)

   Strings should _look like_ strings.


I was suggesting leaving some bread crumbs to lead the 
maintenance programmer "home".


-- 
    Tad McClellan                          SGML consulting
    tadmc@metronet.com                     Perl programming
    Fort Worth, Texas


------------------------------

Date: 30 Dec 2000 15:41:46 GMT
From: anno4000@lublin.zrz.tu-berlin.de (Anno Siegel)
Subject: Re: Numeric comparison fails on numbers?
Message-Id: <92kvnq$6ch$1@mamenchi.zrz.TU-Berlin.DE>

Garry Williams <garry@zvolve.com> wrote in comp.lang.perl.misc:
>On 29 Dec 2000 19:28:37 -0600, Tony Curtis <tony_curtis32@yahoo.com> wrote:
>>>> On Sat, 30 Dec 2000 01:21:33 GMT,
>>>> sjs@linux.ca (Steven Smolinski) said:
>>
>>> I've managed to solve my problem by rounding the figure I test to an
>>> appropriate number of significant digits first:
>>
>>> $sum = sprintf "%.1f", $sum;
>>
>>> Then I can test numerically against 2, or 2.0, or whatever.
>>
>>The usual way is to test the value to see how closely it approaches a
>>limiting value against a sufficiently small delta:
>>
>>    my $delta = 0.0001;                 # or however close you want to get
>>    my $limit = 2.0;                    # in this case
>>
>>    if (abs($sum - $limit) < $delta) {
>>      hurrah();
>>    } else {
>>      boo();
>>    }
>
>But isn't that the *effect* of rounding to some "appropriate" number
>of digits?  

Not really.  Rounding can have different outcomes for two arbitrarily
close values, while the delta method always declares two values equal
if they are close enough.

Anno


------------------------------

Date: Tue, 02 Jan 2001 13:28:21 GMT
From: Gordon.Haverland@agric.gov.ab.ca
Subject: Re: Numeric comparison fails on numbers?
Message-Id: <3a51d62d.340354078@news.gov.ab.ca>

On Fri, 29 Dec 2000 23:21:15 GMT, sjs@linux.ca (Steven Smolinski)
wrote:

>I'm trying to wrap my brain around how perl DWIMs scalars from strings
>to numbers.  For instance, if I add up a few stringified numbers, and
>then compare them against a number, should I use a numerical
>comparison? 

There are (at least) 2 kinds of numbers on computers.  Integers and
floating point are the 2 most common.

While it is possible to exactly represent counting numbers (integers)
as floating point (for "smallish integers"), the same cannot be said
in general for any fractional part of a number.  For example, 0.1
(base 10) doesn't translate into floating point binary very well.

A well known consequence of this is that:
 1.0 != 3.0 * (1.0 / 3.0)

The one third can't be represented in floating point binary, so no
matter how it is converted into binary, when you multiply it by 3 you
cannot get 1.0.

Gord



------------------------------

Date: 3 Jan 2001 14:07:50 GMT
From: abigail@foad.org (Abigail)
Subject: Re: Numeric comparison fails on numbers?
Message-Id: <slrn956chm.f94.abigail@tsathoggua.rlyeh.net>

Gordon.Haverland@agric.gov.ab.ca (Gordon.Haverland@agric.gov.ab.ca) wrote
on MMDCLXXXI September MCMXCIII in <URL:news:3a51d62d.340354078@news.gov.ab.ca>:
{} On Fri, 29 Dec 2000 23:21:15 GMT, sjs@linux.ca (Steven Smolinski)
{} wrote:
{} 
{} >I'm trying to wrap my brain around how perl DWIMs scalars from strings
{} >to numbers.  For instance, if I add up a few stringified numbers, and
{} >then compare them against a number, should I use a numerical
{} >comparison? 
{} 
{} There are (at least) 2 kinds of numbers on computers.  Integers and
{} floating point are the 2 most common.
{} 
{} While it is possible to exactly represent counting numbers (integers)
{} as floating point (for "smallish integers"), the same cannot be said
{} in general for any fractional part of a number.  For example, 0.1
{} (base 10) doesn't translate into floating point binary very well.
{} 
{} A well known consequence of this is that:
{}  1.0 != 3.0 * (1.0 / 3.0)
{} 
{} The one third can't be represented in floating point binary, so no
{} matter how it is converted into binary, when you multiply it by 3 you
{} cannot get 1.0.


That is of course only the case if you perform the division 1.0 / 3.0
first, store the result in a float, and nothing but a float, and then
multiply that with 3.0.

There are, of course, other ways to calculate the result of the expression,
which will get 1.0 exactly.




Abigail
-- 
$_ = "\x3C\x3C\x45\x4F\x54";
print if s/<<EOT/<<EOT/e;
Just another Perl Hacker
EOT


------------------------------

Date: 30 Dec 2000 02:10:50 GMT
From: index@index (--index--)
Subject: O.T.
Message-Id: <92jg7a$lcl026@SGI3651ef0.iddeo.es>

--- INDEX ---

New site with a lot of resources for you

please visit us!

Nuevo site con un monton de recursos para ti

por favor visitanos!

http://usuarios.tripod.es/web_index


------------------------------

Date: Mon, 1 Jan 2001 07:28:08 -0600
From: "Kory Roberts" <kaptainkory@yahoo.com>
Subject: Odd sorting behavior...
Message-Id: <%u%36.7028$Uv2.1096546@nntp2.onemain.com>

I have written a script to keep high scores and have found a bug in my code
that I simply cannot figure out.  I have focused in on the problem using an
example script.

In a plain text file I have the following records:

c|1
a|1
b|1

I am reading the records into an array, @scores_data.  Then I am adding on a
new record and sorting the list according to the numbers only:

unshift (@scores_data, 'a|2');

@scores_data = map  { $_->[0] }
      sort { $a->[1] <=> $b->[1] }
      map  { [ $_, (split /\|/)[1] ] } @scores_data;

Then I am just saving the new data back to the file.  Now the problem:
after I call the script for the 4th time, the first 3 records start
"cycling."  Like this:

b|1
c|1
a|1
(more records here)

Then:

a|1
b|1
c|1
(more records here)

Then it just keeps cycling after each call.

Is there at all a way to stop this?  I have tried numerous sorting routines.
Also, I have found that using push() rather than unshift() seems to solve
the problem, but it creates another problem for this particular script.  The
nice thing about the unshift() function is that it "drops" the new record
atop the records with an equal score.  (Hope that last bit makes sense).  I
suppose I'm just losing my creativity in figuring this out.  Thanks for the
help.

Kory




------------------------------

Date: Tue, 2 Jan 2001 09:44:58 +1100
From: mgjv@tradingpost.com.au (Martien Verbruggen)
Subject: Re: Odd sorting behavior...
Message-Id: <slrn95223a.6lr.mgjv@martien.heliotrope.home>

On Mon, 1 Jan 2001 07:28:08 -0600,
	Kory Roberts <kaptainkory@yahoo.com> wrote:
> 
> In a plain text file I have the following records:
> 
> c|1
> a|1
> b|1
> 
> I am reading the records into an array, @scores_data.  Then I am adding on a
> new record and sorting the list according to the numbers only:
> 
> unshift (@scores_data, 'a|2');
> 
> @scores_data = map  { $_->[0] }
>       sort { $a->[1] <=> $b->[1] }
>       map  { [ $_, (split /\|/)[1] ] } @scores_data;
> 
> Then I am just saving the new data back to the file.  Now the problem:
> after I call the script for the 4th time, the first 3 records start
> "cycling."  Like this:
> 
> b|1
> c|1
> a|1
> (more records here)
> 
> Then:
> 
> a|1
> b|1
> c|1
> (more records here)
> 
> Then it just keeps cycling after each call.

Well, I don't know which version of Perl you're using, but 5.6.0 and
5.005_03 and 5.004_05 all are stable with the data you provide.

#!/opt/perl5.00405/bin/perl -wl
#!/opt/perl/bin/perl5.00503 -wl
#!/usr/local/bin/perl -wl
use strict;

my @a = <DATA>;
chomp @a;
for (1 .. 5)
{
    @a = map  { $_->[0] }
         sort { $a->[1] <=> $b->[1] }
         map  { [ $_, (split /\|/)[1] ] } @a;

    print for @a;
    print "";
}

__DATA__
c|1
a|1
b|1

No matter wich version of Perl I use, and how large the number of
iterations, I still get a stable sort with the data you provide. I
believe that perl's internal sort is stable, at least in 5.6.0, but I'm
not 100 % sure about that. There have been discussions on this in the
past on this group. Maybe check deja to find a few. One of those is

> Is there at all a way to stop this?  I have tried numerous sorting routines.

To stop it, you'd need a stable sort, i.e. one that doesn't change the
order of the elements if they are equal with respect to the sort key (in
this case the number behind the |). There isn't anything you can do to
provide one, apart from writing a sort yourself, and not using Perl's
builtin, _or_ making sure Perl's builtin sort() for your version is
stable. Again: check deja to find the discussions about this.

BTW, what do you mean, you tried numerous sorting routines? You mean you
wrote your own sort(), or are you talking about the thing you supply to
sort? That isn't a sorting routine, just a comparison to tell sort which
element is larger than another element.

> Also, I have found that using push() rather than unshift() seems to solve

I'm not at all sure that I understand what you are saying here..

> the problem, but it creates another problem for this particular script.  The
> nice thing about the unshift() function is that it "drops" the new record
> atop the records with an equal score.  (Hope that last bit makes sense).  I

Not to me. Maybe if you show us some code it'll become clearer.

> suppose I'm just losing my creativity in figuring this out.  Thanks for the
> help.

Martien
-- 
Martien Verbruggen              | 
Interactive Media Division      | You can't have everything, where
Commercial Dynamics Pty. Ltd.   | would you put it?
NSW, Australia                  | 


------------------------------

Date: 2 Jan 2001 00:43:21 GMT
From: Ilmari Karonen <iltzu@sci.invalid>
Subject: Re: Odd sorting behavior...
Message-Id: <978395221.13270@itz.pp.sci.fi>

In article <slrn95223a.6lr.mgjv@martien.heliotrope.home>, Martien Verbruggen wrote:
>
>    @a = map  { $_->[0] }
>         sort { $a->[1] <=> $b->[1] }
>         map  { [ $_, (split /\|/)[1] ] } @a;
>
 [snip]
>
>To stop it, you'd need a stable sort, i.e. one that doesn't change the
>order of the elements if they are equal with respect to the sort key (in
>this case the number behind the |). There isn't anything you can do to
>provide one, apart from writing a sort yourself, and not using Perl's
>builtin, _or_ making sure Perl's builtin sort() for your version is
>stable. Again: check deja to find the discussions about this.

Actually, there is something the OP could do:

  my $i = 0;
  @a = map  { $_->[0] }
       sort { $a->[1] <=> $b->[1] or $a->[2] <=> $b->[2] }
       map  { [ $_, (split /\|/)[1], $i++ ] } @a;

Or one could use a GRT instead of the ST:

  my $i = 0;
  @a = map  { unpack "x4a*", $_ }
       sort
       map  { pack "nna*", (split /\|/)[1], $i++, $_ } @a;

(But the OP really should read the docs for pack() before using this.)

-- 
Ilmari Karonen -- http://www.sci.fi/~iltzu/
"Get real!  This is a discussion group, not a helpdesk.  You post
 something, we discuss its implications.  If the discussion happens to
 answer a question you've asked, that's incidental." -- nobull in clpm



------------------------------

Date: Mon, 1 Jan 2001 18:51:57 -0600
From: "Kory Roberts" <kaptainkory@yahoo.com>
Subject: Re: Odd sorting behavior...
Message-Id: <cw946.209$pA5.147372@nntp1.onemain.com>

Martien,
Thanks for the help, but still not there yet.  I have modified the code you
offered so that it does illustrate the problem I'm having.

my @a = <DATA>;
chomp @a;

for (1..5) {
    unshift @a, 'd|2';

    @a = map  { $_->[0] }
         sort { $a->[1] <=> $b->[1] }
         map  { [ $_, (split /\|/)[1] ] } @a;

     foreach (@a) {
          print;
          print "\n";
     }
     print "\n";
}

__DATA__
c|1
a|1
b|1

The sorting is perfect until the 4th iteration which outputs this:

b|1
c|1
a|1
d|2
d|2
d|2
d|2

So why are the first 3 records changing order?  I want it to stay "c|1, a|1,
b|1".

I am using ActiveState Perl 5.6.0.620 on Windows 2000.  Using $] gives me
5.006.

Now, as something of an aside to illustrate why I'm using unshift() rather
than push()...  Suppose I have the following records:

jim|20
ben|40
pam|60

If I add a new record, "chad|60", using unshift() and then sort, I get the
order I want...because "chad" (the most recent record) will be listed before
"pam" (an older record):

jim|20
ben|40
chad|60
pam|60

With push(), "pam" would be listed before "chad" which is not the behavior I
want.

> > I have tried numerous sorting routines.
>
> BTW, what do you mean, you tried numerous sorting routines?

By this, I ment that I have tried different sorting comparisons using perl's
sort() function.  But I think it's somehow a combination of the unshift()
and sort() together that is creating this problem...  Thanks.

Kory




------------------------------

Date: Tue, 2 Jan 2001 13:06:31 +1100
From: mgjv@tradingpost.com.au (Martien Verbruggen)
Subject: Re: Odd sorting behavior...
Message-Id: <slrn952dt7.6lr.mgjv@martien.heliotrope.home>

On 2 Jan 2001 00:43:21 GMT,
	Ilmari Karonen <iltzu@sci.invalid> wrote:
> In article <slrn95223a.6lr.mgjv@martien.heliotrope.home>, Martien Verbruggen wrote:
>>
>>    @a = map  { $_->[0] }
>>         sort { $a->[1] <=> $b->[1] }
>>         map  { [ $_, (split /\|/)[1] ] } @a;
>>
>  [snip]
>>
>>To stop it, you'd need a stable sort, i.e. one that doesn't change the
>>order of the elements if they are equal with respect to the sort key (in
>>this case the number behind the |). There isn't anything you can do to
>>provide one, apart from writing a sort yourself, and not using Perl's
>>builtin, _or_ making sure Perl's builtin sort() for your version is
>>stable. Again: check deja to find the discussions about this.
> 
> Actually, there is something the OP could do:
> 
>   my $i = 0;
>   @a = map  { $_->[0] }
>        sort { $a->[1] <=> $b->[1] or $a->[2] <=> $b->[2] }
>        map  { [ $_, (split /\|/)[1], $i++ ] } @a;

Yep, good trick. I actually thought of that later on as well, but you
beat me to it :)

Martien
-- 
Martien Verbruggen              | 
Interactive Media Division      | I used to have a Heisenbergmobile.
Commercial Dynamics Pty. Ltd.   | Every time I looked at the
NSW, Australia                  | speedometer, I got lost.


------------------------------

Date: Tue, 2 Jan 2001 13:15:41 +1100
From: mgjv@tradingpost.com.au (Martien Verbruggen)
Subject: Re: Odd sorting behavior...
Message-Id: <slrn952eed.6lr.mgjv@martien.heliotrope.home>

On Mon, 1 Jan 2001 18:51:57 -0600,
	Kory Roberts <kaptainkory@yahoo.com> wrote:

Ilmari Karonen has already posted a solution that you can use to impose
the order that is already there, and basically make your sorting
algorithm stable 9although you're not making it stable as such, but
you're adding an extra field to sort on, which is a sequence number)

I'll repeat that solution here by modifying what you have:

> my @a = <DATA>;
> chomp @a;
> 
> for (1..5) {

      my $i = 0;

>     unshift @a, 'd|2';
> 
>     @a = map  { $_->[0] }
          sort { $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2] }
          map  { [ $_, (split /\|/)[1], $i++ ] } @a;
> 
>      foreach (@a) {
>           print;
>           print "\n";
>      }
>      print "\n";
> }
> 
> __DATA__
> c|1
> a|1

> So why are the first 3 records changing order?  I want it to stay "c|1, a|1,
> b|1".

because the sorting algorithm that Perl uses isn't stable, which means
that there is no guarantee that elements which are 'equal' according to
the sort key remain in the order that they are in. A stable algorithm
does guarantee that.

> I am using ActiveState Perl 5.6.0.620 on Windows 2000.  Using $] gives me
> 5.006.
> 
> Now, as something of an aside to illustrate why I'm using unshift() rather
> than push()...  Suppose I have the following records:
> 
> jim|20
> ben|40
> pam|60
> 
> If I add a new record, "chad|60", using unshift() and then sort, I get the
> order I want...because "chad" (the most recent record) will be listed before
> "pam" (an older record):

If the 'age' of the record is important to the sorting order, then maybe
you should insert a serial number, or a timestamp in the records as
well. The above solution will work as well, but it requires you to
generate these numbers over and over again, and once they are out of
order, thay can't be put back in order. If you have a third field in
each record with the output of the time() function, or a simple
incremental serial number, then you can use that as a sort criterium:

     @a = map  { $_->[0] }
          sort { $a->[1] <=> $b->[1] || $b->[2] <=> $a->[2] }
          map  { [ $_, (split /\|/)[1] ] } @a;

(Note the reversal of $a and $b in the secondary comparison in the sort
sub).

Martien
-- 
Martien Verbruggen              | My friend has a baby. I'm writing
Interactive Media Division      | down all the noises the baby makes so
Commercial Dynamics Pty. Ltd.   | later I can ask him what he meant -
NSW, Australia                  | Steven Wright


------------------------------

Date: Mon, 1 Jan 2001 20:12:59 -0600
From: "Kory Roberts" <kaptainkory@yahoo.com>
Subject: Re: Odd sorting behavior...
Message-Id: <2Ia46.7225$Uv2.1312138@nntp2.onemain.com>


"Ilmari Karonen" <iltzu@sci.invalid> wrote in message
news:978395221.13270@itz.pp.sci.fi...
> In article <slrn95223a.6lr.mgjv@martien.heliotrope.home>, Martien
Verbruggen wrote:

> Actually, there is something the OP could do:
>
>   my $i = 0;
>   @a = map  { $_->[0] }
>        sort { $a->[1] <=> $b->[1] or $a->[2] <=> $b->[2] }
>        map  { [ $_, (split /\|/)[1], $i++ ] } @a;
>

YES!  This has done the trick!  Thanks Ilmari.

Kory




------------------------------

Date: Tue, 02 Jan 2001 04:47:36 GMT
From: Uri Guttman <uri@sysarch.com>
Subject: Re: Odd sorting behavior...
Message-Id: <x766jya7bs.fsf@home.sysarch.com>

>>>>> "MV" == Martien Verbruggen <mgjv@tradingpost.com.au> writes:

  MV> On 2 Jan 2001 00:43:21 GMT,
  MV> 	Ilmari Karonen <iltzu@sci.invalid> wrote:
  >> 
  >> Actually, there is something the OP could do:
  >> 
  >> my $i = 0;
  >> @a = map  { $_->[0] }
  >> sort { $a->[1] <=> $b->[1] or $a->[2] <=> $b->[2] }
  >> map  { [ $_, (split /\|/)[1], $i++ ] } @a;

  MV> Yep, good trick. I actually thought of that later on as well, but you
  MV> beat me to it :)

and that is well documented in our sort paper (on sysarch.com). it is a
common way to force a stable sort when you aren't using a stable
algorithm. perl's sort is not defined (as if anything in perl is
defined! :) to be stable but the newest algorithm used is a mergesort
which is stable. but you should not rely upon that as perl could pick
another algorithm in the future which is not stable.

uri

-- 
Uri Guttman  ---------  uri@sysarch.com  ----------  http://www.sysarch.com
SYStems ARCHitecture, Software Engineering, Perl, Internet, UNIX Consulting
The Perl Books Page  -----------  http://www.sysarch.com/cgi-bin/perl_books
The Best Search Engine on the Net  ----------  http://www.northernlight.com


------------------------------

Date: 2 Jan 2001 10:51:18 GMT
From: abigail@foad.org (Abigail)
Subject: Re: Odd sorting behavior...
Message-Id: <slrn953cl6.e2g.abigail@tsathoggua.rlyeh.net>

Martien Verbruggen (mgjv@tradingpost.com.au) wrote on MMDCLXXX September
MCMXCIII in <URL:news:slrn95223a.6lr.mgjv@martien.heliotrope.home>:
?? 
?? No matter wich version of Perl I use, and how large the number of
?? iterations, I still get a stable sort with the data you provide. I
?? believe that perl's internal sort is stable, at least in 5.6.0, but I'm
?? not 100 % sure about that. There have been discussions on this in the
?? past on this group. Maybe check deja to find a few. One of those is


No, the sort provided by Perl (qsort for pre-5.6.0, own implementation
of quicksort in 5.6.* and mergesort for 5.7) is only quaranteed to be
stable in 5.7.



Abigail
-- 
BEGIN {$^H {join "" => ("a" .. "z") [8, 13, 19, 4, 6, 4, 17]} = sub
           {["", "Just ", "another ", "Perl ", "Hacker\n"] -> [shift]};
       $^H = hex join "" => reverse map {int ($_ / 2)} 0 .. 4}
print 1, 2, 3, 4;


------------------------------

Date: Wed, 3 Jan 2001 17:55:00 +1100
From: mgjv@tradingpost.com.au (Martien Verbruggen)
Subject: Re: Odd sorting behavior...
Message-Id: <slrn955j64.edk.mgjv@martien.heliotrope.home>

On 2 Jan 2001 10:51:18 GMT,
	Abigail <abigail@foad.org> wrote:
> Martien Verbruggen (mgjv@tradingpost.com.au) wrote on MMDCLXXX September
> MCMXCIII in <URL:news:slrn95223a.6lr.mgjv@martien.heliotrope.home>:
> ?? 
> ?? iterations, I still get a stable sort with the data you provide. I
> ?? believe that perl's internal sort is stable, at least in 5.6.0, but I'm
> 
> No, the sort provided by Perl (qsort for pre-5.6.0, own implementation
> of quicksort in 5.6.* and mergesort for 5.7) is only quaranteed to be
> stable in 5.7.

Ah, yes, thanks. I knew I had read something about perl having a stable
sort algorithm. I just couldn't exactly remember whether it was
implemented in 5.6.0 or whether it was in the development versions.

Martien
-- 
Martien Verbruggen              | 
Interactive Media Division      | 
Commercial Dynamics Pty. Ltd.   | "Mr Kaplan. Paging Mr Kaplan..."
NSW, Australia                  | 


------------------------------

Date: 16 Sep 99 21:33:47 GMT (Last modified)
From: Perl-Users-Request@ruby.oce.orst.edu (Perl-Users-Digest Admin) 
Subject: Digest Administrivia (Last modified: 16 Sep 99)
Message-Id: <null>


Administrivia:

The Perl-Users Digest is a retransmission of the USENET newsgroup
comp.lang.perl.misc.  For subscription or unsubscription requests, send
the single line:

	subscribe perl-users
or:
	unsubscribe perl-users

to almanac@ruby.oce.orst.edu.  

| NOTE: The mail to news gateway, and thus the ability to submit articles
| through this service to the newsgroup, has been removed. I do not have
| time to individually vet each article to make sure that someone isn't
| abusing the service, and I no longer have any desire to waste my time
| dealing with the campus admins when some fool complains to them about an
| article that has come through the gateway instead of complaining
| to the source.

To submit articles to comp.lang.perl.announce, send your article to
clpa@perl.com.

To request back copies (available for a week or so), send your request
to almanac@ruby.oce.orst.edu with the command "send perl-users x.y",
where x is the volume number and y is the issue number.

For other requests pertaining to the digest, send mail to
perl-users-request@ruby.oce.orst.edu. Do not waste your time or mine
sending perl questions to the -request address, I don't have time to
answer them even if I did know the answer.


------------------------------
End of Perl-Users Digest V9 Issue 5237
**************************************


home help back first fref pref prev next nref lref last post