sort double-dimensional array by column

Discussion in 'Ruby' started by Mr_Tibs, Oct 12, 2007.

  1. Mr_Tibs

    Mr_Tibs Guest

    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
     
    Mr_Tibs, Oct 12, 2007
    #1
    1. Advertising

  2. Mr_Tibs

    John Woods Guest

    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
    > 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
    >
    >
    >
    >
     
    John Woods, Oct 12, 2007
    #2
    1. Advertising

  3. Mr_Tibs

    mortee Guest

    Mr_Tibs wrote:
    > 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
     
    mortee, Oct 12, 2007
    #3
  4. Mr_Tibs

    Mr_Tibs Guest

    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
     
    Mr_Tibs, Oct 12, 2007
    #4
  5. Mr_Tibs

    Mr_Tibs Guest

    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
     
    Mr_Tibs, Oct 12, 2007
    #5
  6. Mr_Tibs

    mortee Guest

    Mr_Tibs wrote:
    > 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
     
    mortee, Oct 12, 2007
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.

Share This Page