How #ruby-lang approximates the corporate environment

| | Comments (9)

Original Request:

I'd like to sort an array of strings numerically...

Modifications:

... but that doesn't handle letters (non-number strings)
... mine was shorter, but it uses an intermediate variable
... nice, but how do you get the digits before the letters?

My final version:

%w(z A 1 10 2 b).sort_by { |s| [ s[0], s.to_i, s ] }

(ugh)

Update:

kodis did a good job pointing out that I shouldn't blog at 2am. The above code is buggy. Namely, the first term in the sort_by is flat out wrong and was a quick add right at the end that I didn't do a good job of testing. So, the elegant version is:

%w(z A 1 10 2 b).sort_by { |s| [ s.to_i, s ] }

but the one that will sort numbers first (no idea why still, but hey) is:

%w(z A 1 10 2 b).sort_by { |s| [ s =~ /^\d/ ? 1 : 2, s.to_i, s ] }

still, even that ugly sort_by is vastly better than my first attempt:

%w(z a 1 10 2 b).map {|o| Integer(o) rescue o }.partition { |o|
  Fixnum === o }.map { |a| a.sort }.flatten.map { |o| o.to_s }

blech!

9 Comments

Two questions: 1. I'm not sure that "o" should really be there, did you have something else in mind? My Ruby complains about it. 2. What if the array has nil entries?

"2. What if the array has nil entries?"

%w(z A 1 10 2 b).compact.sortby { |s| [ s[0], s.toi, o ] }

3am edits... sorry, the errant o is fixed.

as far as nil goes... um. I think you actually fail to see my real point, which is the "what ifs" and the like kill the soul.

I guess I should have put a smiley next to my comment. I do see your point, so I just added one more whatif. :)

But in a way the whatifs are there, so another question is, what is the most elegant way to deal with them. I happened to be dealing with this problem recently, where I had a double array that was supposed to represent a spreadsheet, so I wanted the "user" to be able to add any entry in any column and row of the array, resulting in many nil elements in my arrays that I constantly had to deal with. I am really not sure what the most elegant way to deal with the situation is. I guess it depends on each situation.

How does one create new paragraphs in the comments here?

"How does one create new paragraphs in the comments here?"

Ignore this. It's just that the comment preview does not show the comment exactly as it will show up, in particular it does not show paragraphs properly.

That's very elegant and all, but there are two things that I don't understand:

  • How does the sortby method interpret the array that's generated in the block? The documentation for the sortby method isn't very clear on this.

  • Shouldn't 2 fall between 1 and 10?

$ ruby -e 'p %w(z A 1 10 2 b).sortby { |s| [ s[0], s.toi, s ] }' ["1", "10", "2", "A", "b", "z"]

damnit. you're right. I shouldn't blog at 2+ am.

The real problem is that true, false, and nil don't have defined, so I couldn't just do a regex or other simple test and have it be nice and elegant looking. :(

As for your first question, sort_by is essentially a "schwartzian transform" from perl but made pretty. Look it up in wikipedia for both a ruby and perl example.

Still not quite there :)

It doesn't handle negative numbers properly.

I. don't. care.

Leave a comment