sort double-dimensional array by column

M

Mr_Tibs

Hi,

I have a [m X n] double-dimensional array in Ruby and I'm trying to
sort the entries (rows) by the 6-th column, which is a DateTime
object. Things get a little bit complicated, since I might have a nil
value in that column. If that happens, then I want to sort by the 7-th
column.
This is what I have so far:

cset_arr = cset_arr.sort do |x, y|
if x[5].nil? && y[5].nil?
x[6] <=> y[6]
elsif x[5].nil? && !y[5].nil?
y[5] # ???
elsif !x[5].nil? && y[5].nil?
x[5] # ???
elsif !x[5].nil? && !y[5].nil?
x[5] <=> y[5]
end
end

For the second and third if statements, I don't know how to "select"
that value. So, for example, if both 6-th columns are nil, then
compare by the 7-th column (first if). But, if the first record has a
nil 6-th column and the second record has a non-nil 6-th column, then
how do I set the second record as being the "selected" one of the two?
The current form (e.g. y[5]) does not work.

Thanks,
Tiberiu
 
J

John Woods

If I understand what you're after, I'd say in the 2nd & 3rd conditions,
you'd want to always treat nil as being less than a non-nil value. So
always return -1 and 1 respectively. As an aside, you can get rid of the
!x.nil? checks because the previous conditions assure that state...

cset_arr = cset_arr.sort do |x, y|
if x[5].nil? && y[5].nil?
x[6] <=> y[6]
elsif x[5].nil?
-1
elsif y[5].nil?
1
else
x[5] <=> y[5]
end
end


-----Original Message-----
From: Mr_Tibs
Sent: 10/11/2007 07:15 PM
 
M

mortee

Mr_Tibs said:
Hi,

I have a [m X n] double-dimensional array in Ruby and I'm trying to
sort the entries (rows) by the 6-th column, which is a DateTime
object. Things get a little bit complicated, since I might have a nil
value in that column. If that happens, then I want to sort by the 7-th
column.
This is what I have so far:

cset_arr = cset_arr.sort do |x, y|
if x[5].nil? && y[5].nil?
x[6] <=> y[6]
elsif x[5].nil? && !y[5].nil?
y[5] # ???
elsif !x[5].nil? && y[5].nil?
x[5] # ???
elsif !x[5].nil? && !y[5].nil?
x[5] <=> y[5]
end
end

What about this one?

cset_arr.sort_by{|row| [ row[5] || DateTime.new, row[6] ] }

Comparing two arrays returns the comparison of the first differing pair
of respective elements. DateTime.new returns some value far in the past,
I guess the lowest possible value. So if both dates are nil, then the
first value in the sort key become the same (this default DateTime
value), thus the 7th column gets compared. Otherwise nil gets replaced
by a value which is most probably lower than any meaningful one.

mortee
 
M

Mr_Tibs

Hi James,

Thanks for the reply. It was what I needed (with a small correction:
inverse -1 and 1). I didn't read the Array.sort doc properly and
didn't know what I supposed to return.

Thanks,
Tiberiu
 
M

Mr_Tibs

Thanks mortee. That sort of worked. Unfortunately, it puts those
entries that have the 6-th column = nil, at the start of the sorted
array (instead of at the end). I don't really understand the technique
used. You are sorting by row, but you are somehow defining and using
an array with 2 elements (that's what the square brackets do, right?).

Tiberiu
 
M

mortee

Mr_Tibs said:
Thanks mortee. That sort of worked. Unfortunately, it puts those
entries that have the 6-th column = nil, at the start of the sorted
array (instead of at the end). I don't really understand the technique
used. You are sorting by row, but you are somehow defining and using
an array with 2 elements (that's what the square brackets do, right?).

Yes. Your code seemed like you want to fall back to the 7th column for
ordering when the 6th column is nil in both rows to compare.

If you do a sort_by, then it'll sort the items (in this case rows) based
on the value the block returns for the item passed to it. And comparing
arrays works this way: if the first elements differ, then their order
determines the final ordering; if they are the same, then the rest of
the arrays get compared, all the way through the last element.

So if you provide the mentioned two-element array as a sort key for your
rows, then the result will be almost what your original code did.
Actually, in the meantime I noticed that when the 6th column is non-nil
and equal in both rows to compare, your code returns equal ordering
independently of the 7th column's values - while my code falls back to
them in this case too.

Reagrding your problem with rows with nil in the 6th column going to the
start: naturally, sort will yield an ascending order, and the default
value substituted in my code is the lowest possible, so they'll get
sorted low (that is, to the start). You're of course free to specify any
default value you like, so that they get sorted to where you want them.

mortee
 

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,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top