Sorting a string...

D

Daniel Waite

I was porting a small Python script over to Ruby and realized Ruby does
not sort strings as I expected it would.

'cba'.sort # ["cba"]

So I wrote this...

class String

def sort
bytes = Array.new
self.each_byte { |byte| bytes << byte }
bytes.sort.collect { |byte| byte.chr }.join
end

end

'cba'.sort # "abc"

It's fairly clean, but I don't like the bytes = and self.each_byte bits.
It feels like there should be a way to say something like...

self.each_byte(&:collect).sort.collect { |byte| byte.chr }.join

Or something like that. I think some of the frustration comes from
Python seemingly being able to do this "out of the box." Unless, of
course, the following Python code generates an array of single
characters and not a single array with two strings (in which case Ruby
CAN do the same):

letters = list(state1 + state2) # I assume this is [ s1, s2 ]
letters.sort()
key = "".join(letters)

Any ideas?
 
D

David Mullet

Daniel said:
I was porting a small Python script over to Ruby and realized Ruby does
not sort strings as I expected it would.

'cba'.sort # ["cba"]

So I wrote this...

class String

def sort
bytes = Array.new
self.each_byte { |byte| bytes << byte }
bytes.sort.collect { |byte| byte.chr }.join
end

end

'cba'.sort # "abc"

It's fairly clean, but I don't like the bytes = and self.each_byte bits.
It feels like there should be a way to say something like...

self.each_byte(&:collect).sort.collect { |byte| byte.chr }.join

Or something like that. I think some of the frustration comes from
Python seemingly being able to do this "out of the box." Unless, of
course, the following Python code generates an array of single
characters and not a single array with two strings (in which case Ruby
CAN do the same):

letters = list(state1 + state2) # I assume this is [ s1, s2 ]
letters.sort()
key = "".join(letters)

Any ideas?

class String
def sort
self.split('').sort.join
end
end

'cba'.sort #=> "abc"
 
D

Daniel Waite

David said:
class String
def sort
self.split('').sort.join
end
end

'cba'.sort #=> "abc"

Brilliant! Thanks, David. I love this community. :)

I had tried split, but in haste, with no arguments. However, after
reading the docs again I see no arguments equals a space.

Interesting how the documentation has a perfect example:

"hello".split(//) #=> ["h", "e", "l", "l", "o"]

When writing that extension I kept thinking, all I need is an array, how
can I get one? Now I know!
 
D

David A. Black

Hi --

I was porting a small Python script over to Ruby and realized Ruby does
not sort strings as I expected it would.

'cba'.sort # ["cba"]

So I wrote this...

class String

def sort
bytes = Array.new
self.each_byte { |byte| bytes << byte }
bytes.sort.collect { |byte| byte.chr }.join
end

end

'cba'.sort # "abc"

I wouldn't overwrite a core method like that; you could end up with
some very unexpected results. It's better to give it a different name.


David

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
* Advancing With Rails, Edison, NJ, November 6-9
* Advancing With Rails, Berlin, Germany, November 19-22
* Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.rubypal.com for details!
 
J

Joel VanderWerf

David said:
Hi --

I was porting a small Python script over to Ruby and realized Ruby does
not sort strings as I expected it would.

'cba'.sort # ["cba"]

So I wrote this...

class String

def sort
bytes = Array.new
self.each_byte { |byte| bytes << byte }
bytes.sort.collect { |byte| byte.chr }.join
end

end

'cba'.sort # "abc"

I wouldn't overwrite a core method like that; you could end up with
some very unexpected results. It's better to give it a different name.

Also, note that String#sort depends on String#to_a being defined, which
is no longer true in 1.9. It's kind of an accident that "cba".sort works
at all.

I guess that means someone will be free to implement String#sort, as
long as they stick to 1.9. Maybe there will be a core implementation
that works as expected?
 
K

Konrad Meyer

--nextPart1561589.L36uTRmXCA
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Quoth Joel VanderWerf:
David said:
Hi --
=20
On Thu, 1 Nov 2007, Daniel Waite wrote:
=20
I was porting a small Python script over to Ruby and realized Ruby does
not sort strings as I expected it would.

'cba'.sort # ["cba"]

So I wrote this...

class String

def sort
bytes =3D Array.new
self.each_byte { |byte| bytes << byte }
bytes.sort.collect { |byte| byte.chr }.join
end

end

'cba'.sort # "abc"
=20
I wouldn't overwrite a core method like that; you could end up with
some very unexpected results. It's better to give it a different name.
=20
Also, note that String#sort depends on String#to_a being defined, which=20
is no longer true in 1.9. It's kind of an accident that "cba".sort works= =20
at all.
=20
I guess that means someone will be free to implement String#sort, as=20
long as they stick to 1.9. Maybe there will be a core implementation=20
that works as expected?
=20
--=20
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Well, anyone who's sorting a string really just wants to sort the component=
=20
letters, so my_str.split('').sort.join('') is the way to go. If they want t=
o=20
add a method to String to simplify this, they can do that.

=2D-=20
Konrad Meyer <[email protected]> http://konrad.sobertillnoon.com/

--nextPart1561589.L36uTRmXCA
Content-Type: application/pgp-signature; name=signature.asc
Content-Description: This is a digitally signed message part.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (GNU/Linux)

iD8DBQBHKRPSCHB0oCiR2cwRAkh/AJ0fwxt4DFEVSEJ9u8voFixSdnqwQwCgyOfH
ZNmeRH4lCQYxnfJim93+A5A=
=aQfL
-----END PGP SIGNATURE-----

--nextPart1561589.L36uTRmXCA--
 
B

Brian Adkins

I wouldn't overwrite a core method like that; you could end up with
some very unexpected results. It's better to give it a different name.

# splort for split sort ;)
def splort s
s.split('').sort!.join('')
end
 
J

John Joyce

Quoth Joel VanderWerf:
David said:
Hi --

On Thu, 1 Nov 2007, Daniel Waite wrote:

I was porting a small Python script over to Ruby and realized
Ruby does
not sort strings as I expected it would.

'cba'.sort # ["cba"]

So I wrote this...

class String

def sort
bytes = Array.new
self.each_byte { |byte| bytes << byte }
bytes.sort.collect { |byte| byte.chr }.join
end

end

'cba'.sort # "abc"

I wouldn't overwrite a core method like that; you could end up with
some very unexpected results. It's better to give it a different
name.

Also, note that String#sort depends on String#to_a being defined,
which
is no longer true in 1.9. It's kind of an accident that "cba".sort
works
at all.

I guess that means someone will be free to implement String#sort, as
long as they stick to 1.9. Maybe there will be a core implementation
that works as expected?

Well, anyone who's sorting a string really just wants to sort the
component
letters, so my_str.split('').sort.join('') is the way to go. If
they want to
add a method to String to simplify this, they can do that.
Presuming an English alphabetic order, perhaps yes.
What about case-sensitivity?
What about other languages? Ordering always depends on little
details. A basic English alphabetic ordering might be an overly
simple use-case. Although, it is a great example of a Ruby one-liner.
Remember unicode support is coming (we hope) to Ruby 2, and 1.9 is
really an unfinished 2.
 
S

Stefan Rusterholz

Daniel said:
I was porting a small Python script over to Ruby and realized Ruby does
not sort strings as I expected it would.

'cba'.sort # ["cba"]

So I wrote this...

If you just want to sort by byte-value (i.e. disregarding the
possibility of a multibyte-encoding and ignoring umlauts etc.), you can
do:
str.unpack("C*").sort.pack("C*")
It's about twice as fast as
str.split(//).sort.join

Regards
Stefan
 
P

Phrogz

The sort! is unnecessary, use sort (no exclamation)

Based on what criterion/criteria?

If there is a desire not to unnecessarily allocate an extra array, the
exclamation point is necessary.

You could say that the split() is unnecessary, because you can just do
this instead:
def splort s
a = []
s.each_byte{ |b| a << b.chr }
a.sort.join('')
end
 
D

devi.webmaster

The sort! is unnecessary, use sort (no exclamation)
Based on what criterion/criteria?

I suppose I wasn't thinking. For some reason sort would be a cheaper
operation than sort!, but sort involves object instantiation, which is
much more expensive. My apologies.
 
B

Brian Adkins

I suppose I wasn't thinking. For some reason sort would be a cheaper
operation than sort!, but sort involves object instantiation, which is
much more expensive. My apologies.

They're actually not that different in this case. I also thought sort!
would be much quicker since it sorts in place, but it doesn't seem to
be when I benchmarked both of them. I just continued using sort! on
principle :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,996
Messages
2,570,238
Members
46,826
Latest member
robinsontor

Latest Threads

Top