Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Array.sort when it's items are String inheritors with redefined <=> works like if not redefined

Reply
Thread Tools

Array.sort when it's items are String inheritors with redefined <=> works like if not redefined

 
 
MiG
Guest
Posts: n/a
 
      10-19-2005
Hello,
I want to have a string which, if in array, will be sorted like numbers=
=20
I wrote this:

-------------------------------------------------------------------------=
----------------

class String2 < String

def <=3D> str2
self.to_i <=3D> str2.to_i
end

end

a =3D [ String2.new('1'), String2.new('10'), String2.new('5') ]

puts a.sort.join(',')

-------------------------------------------------------------------------=
----------------

It produces "1,10,5", but I expected "1,5,10"

Then I wrote a class without String inheritance and it works.
BUT: another strange thing happened:

in `<=3D>': undefined method `to_i' for #<S:0x40020930 @a=3D"10"> =20
(NoMethodError)

to_i method, even if @a is a String, must be explicitely defined.
Moreover "defined". What do you think about it?

-------------------------------------------------------------------------=
----------------

class String2

def initialize a
@a =3D a
end

def <=3D> b
@a.is_a? String # >> true but..
@a.to_i <=3D> b.to_i # .. @a.to_i doesn't work if I don't defin=
e =20
to_i method below
end

def to_i
@a.to_i
end

def to_s
@a
end

end

a =3D [ String2.new('1'), String2.new('10'), String2.new('5') ]

puts a.sort.join(',')

-------------------------------------------------------------------------=
----------------

Thank you,
jan molic


 
Reply With Quote
 
 
 
 
Robert Klemme
Guest
Posts: n/a
 
      10-19-2005
MiG wrote:
> Hello,
> I want to have a string which, if in array, will be sorted like
> numbers
> I wrote this:
>
> ------------------------------------------------------------------------

-----------------
>
> class String2 < String
>
> def <=> str2
> self.to_i <=> str2.to_i
> end
>
> end
>
> a = [ String2.new('1'), String2.new('10'), String2.new('5') ]
>
> puts a.sort.join(',')
>
> ------------------------------------------------------------------------

-----------------
>
> It produces "1,10,5", but I expected "1,5,10"


I think there is an optimization going on that doesn't use <=> for String
and subclasses. This is one of the reasons why it's subclassing of core
classes like String, Array etc. should be done rarely and with care.

In your case you better use sort_by:

>> a=["1","10","5"]

=> ["1", "10", "5"]
>> a.sort_by {|x| x.to_i}

=> ["1", "5", "10"]

This works also if the array contains instances of your subclass. It
might also be more efficient as #to_i is only invoked once per instance
and not once per comparison per compared object.

> Then I wrote a class without String inheritance and it works.
> BUT: another strange thing happened:
>
> in `<=>': undefined method `to_i' for #<S:0x40020930 @a="10">
> (NoMethodError)
>
> to_i method, even if @a is a String, must be explicitely defined.
> Moreover "defined". What do you think about it?


That's not strange. That's perfectly normal. Because there is no default
#to_i method:

>> Object.new.to_i

NoMethodError: undefined method `to_i' for #<Object:0x101d0b28>
from (irb):3
from :0

Kind regards

robert

 
Reply With Quote
 
 
 
 
Yukihiro Matsumoto
Guest
Posts: n/a
 
      10-19-2005
Hi,

In message "Re: Array.sort when it's items are String inheritors with redefined <=> works like if not redefined"
on Wed, 19 Oct 2005 22:28:29 +0900, MiG <(E-Mail Removed)> writes:

|Hello,
| I want to have a string which, if in array, will be sorted like numbers.
|I wrote this:
|
|-----------------------------------------------------------------------------------------
|
|class String2 < String
|
| def <=> str2
| self.to_i <=> str2.to_i
| end
|
|end
|
|a = [ String2.new('1'), String2.new('10'), String2.new('5') ]
|
|puts a.sort.join(',')

Why not use sort_by, much simpler solution?

a = ['1', '10', '5']
puts a.sort_by{|x|x.to_u}.join(',')

matz.


 
Reply With Quote
 
James Edward Gray II
Guest
Posts: n/a
 
      10-19-2005
On Oct 19, 2005, at 8:59 AM, Yukihiro Matsumoto wrote:

> Why not use sort_by, much simpler solution?
>
> a = ['1', '10', '5']
> puts a.sort_by{|x|x.to_u}.join(',')


I believe that second line is supposed to read:

puts a.sort_by{|x|x.to_i}.join(',')

James Edward Gray II



 
Reply With Quote
 
Ara.T.Howard
Guest
Posts: n/a
 
      10-19-2005
On Wed, 19 Oct 2005, MiG wrote:

> Hello,
> I want to have a string which, if in array, will be sorted like numbers. I
> wrote this:
>
> -----------------------------------------------------------------------------------------
>
> class String2 < String
>
> def <=> str2
> self.to_i <=> str2.to_i
> end
>
> end
>
> a = [ String2.new('1'), String2.new('10'), String2.new('5') ]
>
> puts a.sort.join(',')


put the method in Array:

harp:~ > cat a.rb
class Array
def sort_as!
map!{|elem| yield elem}
sort!
self
end
def sort_as
dup.sort!
end
end


a = %w( 1 10 5 )

p a.sort_as{|s| Integer s}
p a.sort_as{|s| Float s}
p a.sort_as{|s| s.reverse }

a.sort_as!{|s| Integer s}
p a


harp:~ > ruby a.rb
["1", "10", "5"]
["1", "10", "5"]
["1", "10", "5"]
[1, 5, 10]

this avoids calling to_i, to_f, or whatever multiple times on the same object,
which will occur if you use either a spacship (<=>) operator or sort_by
approach.


hth.


-a
--
================================================== =============================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| anything that contradicts experience and logic should be abandoned.
| -- h.h. the 14th dalai lama
================================================== =============================



 
Reply With Quote
 
Sean O'Halpin
Guest
Posts: n/a
 
      10-19-2005
On 10/19/05, Ara.T.Howard <(E-Mail Removed)> wrote:
> this avoids calling to_i, to_f, or whatever multiple times on the same ob=

ject,
> which will occur if you use either a spacship (<=3D>) operator or sort_by
> approach.


I thought sort_by was a packaged form of the Schwartzian transform, i.e.

class A
def to_i
puts "in A.to_i"
3
end
end

p [1, 2, 3, 4, 5, A.new].sort_by {|x| x.to_i }
# is equivalent to
p [1, 2, 3, 4, 5, A.new].map{|x| [x.to_i, x]}.sort{|y, z| y[0] <=3D>
z[0]}.map{|x| x[1]}

__END__
in A.to_i
[1, 2, 3, #<A:0x2870f28>, 4, 5]
in A.to_i
[1, 2, 3, #<A:0x2870cd0>, 4, 5]

Regards,

Sean


 
Reply With Quote
 
Yukihiro Matsumoto
Guest
Posts: n/a
 
      10-19-2005
Hi,

In message "Re: Array.sort when it's items are String inheritors with redefined <=> works like if not redefined"
on Wed, 19 Oct 2005 23:06:04 +0900, James Edward Gray II <(E-Mail Removed)> writes:

|> a = ['1', '10', '5']
|> puts a.sort_by{|x|x.to_u}.join(',')
|
|I believe that second line is supposed to read:
|
| puts a.sort_by{|x|x.to_i}.join(',')

Oops, you're right. Thank you for correction.

matz.


 
Reply With Quote
 
Ara.T.Howard
Guest
Posts: n/a
 
      10-19-2005
On Wed, 19 Oct 2005, Sean O'Halpin wrote:

> On 10/19/05, Ara.T.Howard <(E-Mail Removed)> wrote:
>> this avoids calling to_i, to_f, or whatever multiple times on the same object,
>> which will occur if you use either a spacship (<=>) operator or sort_by
>> approach.

>
> I thought sort_by was a packaged form of the Schwartzian transform, i.e.
>
> class A
> def to_i
> puts "in A.to_i"
> 3
> end
> end
>
> p [1, 2, 3, 4, 5, A.new].sort_by {|x| x.to_i }
> # is equivalent to
> p [1, 2, 3, 4, 5, A.new].map{|x| [x.to_i, x]}.sort{|y, z| y[0] <=>
> z[0]}.map{|x| x[1]}
>
> __END__
> in A.to_i
> [1, 2, 3, #<A:0x2870f28>, 4, 5]
> in A.to_i
> [1, 2, 3, #<A:0x2870cd0>, 4, 5]


you are quite right sean - i guess that only applies to the op's original

a.to_i <=> b.to_i

where you could end up doing that more than once.

regards.

-a
--
================================================== =============================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| anything that contradicts experience and logic should be abandoned.
| -- h.h. the 14th dalai lama
================================================== =============================



 
Reply With Quote
 
Ryan Leavengood
Guest
Posts: n/a
 
      10-19-2005
I think you have a bug here, Ara:

On 10/19/05, Ara.T.Howard <(E-Mail Removed)> wrote:
>
> harp:~ > cat a.rb
> class Array
> def sort_as!
> map!{|elem| yield elem}
> sort!
> self
> end
> def sort_as
> dup.sort! #???
> end


How about:

def sort_as(&block)
dup.sort_as!(&block)
end

> end
>
>
> a =3D %w( 1 10 5 )
>
> p a.sort_as{|s| Integer s}
> p a.sort_as{|s| Float s}
> p a.sort_as{|s| s.reverse }
>
> a.sort_as!{|s| Integer s}
> p a


C:\_Ryan\ruby>ruby a.rb
[1, 5, 10]
[1.0, 5.0, 10.0]
["01", "1", "5"]
[1, 5, 10]

I'm not sure it is worth adding such a method, when a map{}.sort would
do the same thing, and is more explicit. Plus we have sort_by to solve
the OP's problem.

Ryan


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
object-like macro used like function-like macro Patrick Kowalzick C++ 5 03-14-2006 03:30 PM
When I turn on my PC, it works, works, works. Problem! Fogar Computer Information 1 01-17-2006 12:57 AM
template-class-id redefined problem saksenaabhishek@rediffmail.com C++ 1 04-01-2005 03:00 PM
After rebooting my PC works, works, works! Antivirus problem? Adriano Computer Information 1 12-15-2003 05:30 AM
Items in Outbox not moving to Sent Items Ben Lord Computer Support 0 10-23-2003 08:47 AM



Advertisments