Hash Sorting

Discussion in 'Ruby' started by Nathan Viswa, Nov 29, 2007.

  1. Nathan Viswa

    Nathan Viswa Guest

    Can not understand how the block after sort works! Need help. thanks.

    h = { "a" => 20, "b" => 30, "c" => 10 }
    puts h.sort #=> [["a", 20], ["b", 30], ["c", 10]]
    puts h.sort {|a,b| a[0]<=>b[0]} # as above
    puts h.sort {|a,b| a[1]<=>b[1]} #=> [["c", 10], ["a", 20], ["b", 30]]

    I:\RubyNV>zzz-tut6-hash.rb
    a
    20
    b
    30
    c
    10

    a
    20
    b
    30
    c
    10

    c
    10
    a
    20
    b
    30

    I:\RubyNV>
    --
    Posted via http://www.ruby-forum.com/.
     
    Nathan Viswa, Nov 29, 2007
    #1
    1. Advertising

  2. Alle gioved=C3=AC 29 novembre 2007, Nathan Viswa ha scritto:
    > Can not understand how the block after sort works! Need help. thanks.
    >
    > h =3D { "a" =3D> 20, "b" =3D> 30, "c" =3D> 10 }
    > puts h.sort #=3D> [["a", 20], ["b", 30], ["c", 10]]
    > puts h.sort {|a,b| a[0]<=3D>b[0]} # as above
    > puts h.sort {|a,b| a[1]<=3D>b[1]} #=3D> [["c", 10], ["a", 20], ["b", 3=

    0]]

    What Hash#sort does is:=20
    * first: convert the hash into a nested array:
    [['a', 20], ['b', 30], ['c', 10]]
    * second: sort that array according to the block.

    In the first call to sort, you don't pass a block to it, so the sorting wil=
    l=20
    be performed by calling the <=3D> of the contents of the array (i.e, on the=
    =20
    key - value arrays). Array#<=3D> compares the contents of the two arrays in=
    =20
    order, returning +1 or -1 as soon as one of the items is different from the=
    =20
    other. For example, ['a', 20]<=3D>['c', 10] returns -1 because 'a'=20
    precedes 'c'. If two entries had the same first element (here this is=20
    impossible since they come from a hash), the second element would be=20
    compared, an so on.

    Your second call to send gives the same result, because you're explicitly=20
    telling sort to compare only the first element of the array. As explained=20
    above, even in the blockless case sort never needs to check the second=20
    element, so the results are the same.

    In the third case, you tell sort to compare the second element of each pair=
    =20
    (i.e, the value in the original hash). This way, the pair ['c', 10] becomes=
    =20
    the first, because 10 is the lesser of the three values; ['a', 20] is the=20
    second because 20 is the middle value and ['b', 30] is the last because 30 =
    is=20
    the greater value.

    I hope this helps

    Stefano
     
    Stefano Crocco, Nov 29, 2007
    #2
    1. Advertising

  3. On Nov 29, 2007 11:09 AM, Nathan Viswa <> wrote:
    > Can not understand how the block after sort works! Need help. thanks.
    >
    > h = { "a" => 20, "b" => 30, "c" => 10 }
    > puts h.sort #=> [["a", 20], ["b", 30], ["c", 10]]
    > puts h.sort {|a,b| a[0]<=>b[0]} # as above
    > puts h.sort {|a,b| a[1]<=>b[1]} #=> [["c", 10], ["a", 20], ["b", 30]]


    As can be read in the documentation:

    Converts hsh to a nested array of [ key, value ] arrays and sorts it,
    using Array#sort.

    This means that sort will convert the array to this (in some order):

    [["a", 20], ["b", 30], ["c", 10]]

    and then call array sort on it. Checking the documentation on Array#sort:


    Returns a new array created by sorting self. Comparisons for the sort
    will be done using the <=> operator or using an optional code block.
    The block implements a comparison between a and b, returning -1, 0, or
    +1. See also Enumerable#sort_by.

    a = [ "d", "a", "e", "c", "b" ]
    a.sort #=> ["a", "b", "c", "d", "e"]
    a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"]


    What this means is that in the block form, whenever the sort algorithm
    needs to compare two elements of the array, it will yield to the block
    passing both elements (remember that each element is itself an array
    of [key,value] generated by the hash) and expecting a -1, 0 or 1
    result, depending on which one you consider to be less than the other
    or if they are equal.

    In the case of the hash example above:

    h.sort {|a,b| a[0]<=>b[0]}

    the block will receive, for example:
    a = ["a", 20]
    b = ["b", 30]

    or

    a = ["a", 20]
    b = ["c", 10]

    or whatever pairs the sorting algorithm needs to compare. Then inside
    the block you need to provide the comparison of the two elements. The
    first example is doing a comparison of the keys, because the first
    element of the pair is the hash key, so:

    a[0] <=> b[0]

    calls the spaceship operator on the keys of the hash. While the second
    one a[1] <=> b[1] compares the values of the hash.

    Hope this makes any sense.

    Jesus.
     
    Jesús Gabriel y Galán, Nov 29, 2007
    #3
  4. Nathan Viswa

    Nathan Viswa Guest

    Nathan Viswa, Nov 29, 2007
    #4
  5. Nathan Viswa

    Nico Ritsche Guest

    Nathan Viswa wrote:
    > Thanks Stefano, Jesus for your time and explanation. Makes sense now.



    Hi,

    I'm also trying to sort a hash, but don't succeed for some reason.

    My hash is build like this:

    hash['key1'] = array_of_database_records_type_1
    hash['key2'] = array_of_database_records_type_2
    hash['key3'] = array_of_database_records_type_3
    hash['key4'] = array_of_database_records_type_4

    ..
    ..

    and so on. The hash's data values are arrays of rails active record
    objects,
    receifed from a find:)all) call, although their type shouldn't be of
    importance when sorting by key, as I do:

    sorted_hash_array = hash.sort

    The array I receive is not sorted by keys at all, in fact its the same
    array I get when I call hash.to_a without any sorting.

    Sitting on this 'simple' problem for a few hours now, having no idea
    what's the problem.

    Any ideas?

    Nico


    --
    Posted via http://www.ruby-forum.com/.
     
    Nico Ritsche, Jan 28, 2008
    #5
  6. Nathan Viswa

    James Tucker Guest

    On 28 Jan 2008, at 17:45, Nico Ritsche wrote:
    >
    > Any ideas?


    hash.to_a.sort
     
    James Tucker, Jan 28, 2008
    #6
  7. Nathan Viswa

    Nico Ritsche Guest

    James Tucker wrote:
    > On 28 Jan 2008, at 17:45, Nico Ritsche wrote:
    >>
    >> Any ideas?

    >
    > hash.to_a.sort


    Tried that, the result is the same, no sorting is happening at all.
    Same as if I just do hash.to_a.
    --
    Posted via http://www.ruby-forum.com/.
     
    Nico Ritsche, Jan 28, 2008
    #7
  8. Nathan Viswa

    Ilan Berci Guest

    Nico Ritsche wrote:
    > James Tucker wrote:
    >> On 28 Jan 2008, at 17:45, Nico Ritsche wrote:
    >>>
    >>> Any ideas?

    >>
    >> hash.to_a.sort

    >
    > Tried that, the result is the same, no sorting is happening at all.
    > Same as if I just do hash.to_a.


    James is correct, the array will be sorted but the hash will remain
    "unsorted". Hashes are random access unsorted collections.. you can't
    "sort" a hash..

    you can however as James suggested, move the elements to a hash and then
    sort the result any way you want..

    irb(main):001:0> h = {1=>2,3=>4,5=>6}
    => {5=>6, 1=>2, 3=>4}
    irb(main):002:0> h.to_a.sort
    => [[1, 2], [3, 4], [5, 6]]
    irb(main):003:0> h.to_a.sort_by {|a,b| b}
    => [[1, 2], [3, 4], [5, 6]]
    irb(main):004:0>
    --
    Posted via http://www.ruby-forum.com/.
     
    Ilan Berci, Jan 28, 2008
    #8
  9. Nathan Viswa

    Ilan Berci Guest

    Ilan Berci wrote:

    >
    > you can however as James suggested, move the elements to a hash and then
    > sort the result any way you want..
    >

    errrr.. I mean move the elements to an array.. sorry for the confusion

    ilan

    --
    Posted via http://www.ruby-forum.com/.
     
    Ilan Berci, Jan 28, 2008
    #9
  10. Nathan Viswa

    Nico Ritsche Guest

    Ilan Berci wrote:
    > Ilan Berci wrote:
    >
    >>
    >> you can however as James suggested, move the elements to a hash and then
    >> sort the result any way you want..
    >>

    > errrr.. I mean move the elements to an array.. sorry for the confusion
    >
    > ilan




    Well, yea, but that is what I did, with no success. The hash.sort
    function
    simply calls .to_a and then sort on the generated array, so it does
    exactly what you and James suggested. Unfortunately the array is not
    sorted when I iterate over it using

    array.each do
    ...
    end

    Is it because iterating like this doesn't preserve the order of array
    elements? I assumed .each do iterates in element order. I will test
    this...
    --
    Posted via http://www.ruby-forum.com/.
     
    Nico Ritsche, Jan 28, 2008
    #10
  11. Ilan Berci wrote:

    >
    > ilan


    irb(main):001:0> h = {1=>2,3=>4,5=>6}
    => {5=>6, 1=>2, 3=>4}
    irb(main):002:0> h.to_a.sort
    => [[1, 2], [3, 4], [5, 6]]
    irb(main):003:0> h.to_a.sort_by {|a,b| b}
    => [[1, 2], [3, 4], [5, 6]]
    irb(main):004:0>

    h.to_a.sort_by {|a,b| b} #sorts by value; the OP wants to sort by key.
    h.to_a.sort_by {|key,value| key}
    #or just
    h.to_a.sort_by {|key|key}

    Regards,

    Siep


    --
    Posted via http://www.ruby-forum.com/.
     
    Siep Korteling, Jan 28, 2008
    #11
  12. Nathan Viswa

    Nico Ritsche Guest

    Siep Korteling wrote:
    > Ilan Berci wrote:
    >
    >>
    >> ilan

    >
    > irb(main):001:0> h = {1=>2,3=>4,5=>6}
    > => {5=>6, 1=>2, 3=>4}
    > irb(main):002:0> h.to_a.sort
    > => [[1, 2], [3, 4], [5, 6]]
    > irb(main):003:0> h.to_a.sort_by {|a,b| b}
    > => [[1, 2], [3, 4], [5, 6]]
    > irb(main):004:0>
    >
    > h.to_a.sort_by {|a,b| b} #sorts by value; the OP wants to sort by key.
    > h.to_a.sort_by {|key,value| key}
    > #or just
    > h.to_a.sort_by {|key|key}
    >
    > Regards,
    >
    > Siep



    array.sort sorts by key, I know that. That's what I'm trying to do, but
    it doesnt work in my case for some reason

    --
    Posted via http://www.ruby-forum.com/.
     
    Nico Ritsche, Jan 28, 2008
    #12
  13. Nathan Viswa

    Nico Ritsche Guest

    Nico Ritsche wrote:
    > Siep Korteling wrote:
    >> Ilan Berci wrote:
    >>
    >>>
    >>> ilan

    >>
    >> irb(main):001:0> h = {1=>2,3=>4,5=>6}
    >> => {5=>6, 1=>2, 3=>4}
    >> irb(main):002:0> h.to_a.sort
    >> => [[1, 2], [3, 4], [5, 6]]
    >> irb(main):003:0> h.to_a.sort_by {|a,b| b}
    >> => [[1, 2], [3, 4], [5, 6]]
    >> irb(main):004:0>
    >>
    >> h.to_a.sort_by {|a,b| b} #sorts by value; the OP wants to sort by key.
    >> h.to_a.sort_by {|key,value| key}
    >> #or just
    >> h.to_a.sort_by {|key|key}
    >>
    >> Regards,
    >>
    >> Siep

    >
    >
    > array.sort sorts by key, I know that. That's what I'm trying to do, but
    > it doesnt work in my case for some reason



    maybe this excerpt of my code helps to clarify what I'm trying to do
    (for those who know rails):

    @parent_items = {}

    @parent_items['teachers'] = Teacher.find:)all)
    @parent_items['prices'] = Price.find:)all)
    @parent_items['general_event_types'] = GeneralEventType.find:)all,
    :conditions => "language_parent_id = id")
    @parent_items['specific_event_types'] = SpecificEventType.find:)all,
    :conditions => "language_parent_id = id")

    pi_array_sorted = @parent_items.to_a.sort

    and the i like to iterate over the elements of the sorted array, so the
    result should look like this:

    pi_array_sorted =
    { 'general_event_types', [GeneralEventType1, GeneralEventType2, ..],
    'prices', [Price1, Price2, ..],
    'specific_event_types', [SpecificEventType1, SpecificEventType2, ..],
    'general_event_types', [Teacher1, Teacher2, ..] }

    So the keys should be in alphabetical order, but they arent, at least
    not when I iterate over the array using

    pi_array_sorted.each do |a|
    ..
    end


    --
    Posted via http://www.ruby-forum.com/.
     
    Nico Ritsche, Jan 28, 2008
    #13
  14. Nico Ritsche wrote:
    > result should look like this:
    >
    > pi_array_sorted =
    > { 'general_event_types', [GeneralEventType1, GeneralEventType2, ..],
    > 'prices', [Price1, Price2, ..],
    > 'specific_event_types', [SpecificEventType1, SpecificEventType2, ..],
    > 'general_event_types', [Teacher1, Teacher2, ..] }
    >
    > So the keys should be in alphabetical order, but they arent, (...)


    Well, they are, if the last 'general_event_types' is substituted with
    'teachers', what it probably should be.
    I guess you want the values sorted.

    I don't now Rails, but hey, it's ruby. You can probably do

    @parent_items['teachers'] = Teacher.find:)all).sort

    in your second and following lines. Or:

    pi_array_sorted = @parent_items.sort.by{|key, value|value.sort!;key}

    to have your subarrays sorted and the keys as well in one go.

    Regards,

    Siep



    --
    Posted via http://www.ruby-forum.com/.
     
    Siep Korteling, Jan 28, 2008
    #14
  15. Nathan Viswa

    Nico Ritsche Guest

    Siep Korteling wrote:
    > Nico Ritsche wrote:
    >> result should look like this:
    >>
    >> pi_array_sorted =
    >> { 'general_event_types', [GeneralEventType1, GeneralEventType2, ..],
    >> 'prices', [Price1, Price2, ..],
    >> 'specific_event_types', [SpecificEventType1, SpecificEventType2, ..],
    >> 'general_event_types', [Teacher1, Teacher2, ..] }
    >>
    >> So the keys should be in alphabetical order, but they arent, (...)

    >
    > Well, they are, if the last 'general_event_types' is substituted with
    > 'teachers', what it probably should be.
    > I guess you want the values sorted.
    >
    > I don't now Rails, but hey, it's ruby. You can probably do
    >
    > @parent_items['teachers'] = Teacher.find:)all).sort
    >
    > in your second and following lines. Or:
    >
    > pi_array_sorted = @parent_items.sort.by{|key, value|value.sort!;key}
    >
    > to have your subarrays sorted and the keys as well in one go.
    >
    > Regards,
    >
    > Siep




    Hi Siep, yeah, that was a typo, the last general_event_types should be
    'teachers'.

    But nevertheless, this is NOT what I get, its what I like to get!
    And I really only want to sort by key, as I explained erlier...

    Thanks,
    Nico
    --
    Posted via http://www.ruby-forum.com/.
     
    Nico Ritsche, Jan 29, 2008
    #15
  16. > pi_array_sorted =
    > { 'general_event_types',  [GeneralEventType1, GeneralEventType2, ..],
    >   'prices',               [Price1, Price2, ..],
    >   'specific_event_types', [SpecificEventType1, SpecificEventType2, ..],
    >   'general_event_types',  [Teacher1, Teacher2, ..] }
    >
    > So the keys should be in alphabetical order, but they arent, at least
    > not when I iterate over the array using
    >


    This code above doesn't create an array, it creates an Hash, and Hash
    doesn't preserve order.
    Do the following:

    pi_array_sorted = [
    ['general_event_types', [GeneralEventType1,
    GeneralEventType2, ..]],
    ['prices', [Price1, Price2, ..]],
    ['specific_event_types', [SpecificEventType1,
    SpecificEventType2, ..]],
    ['general_event_types', [Teacher1, Teacher2, ..]]
    ]

    pi_array_sorted.each do |key,value|
    # do stuff here
    end

    Cheers
     
    Rodrigo Kochenburger, Jan 29, 2008
    #16
  17. Nathan Viswa

    Nico Ritsche Guest

    Rodrigo Kochenburger wrote:
    >> pi_array_sorted =
    >> { 'general_event_types', �[GeneralEventType1, GeneralEventType2, ..],
    >> � 'prices', � � � � � � � [Price1, Price2, ..],
    >> � 'specific_event_types', [SpecificEventType1, SpecificEventType2, ..],
    >> � 'general_event_types', �[Teacher1, Teacher2, ..] }
    >>
    >> So the keys should be in alphabetical order, but they arent, at least
    >> not when I iterate over the array using
    >>

    >
    > This code above doesn't create an array, it creates an Hash, and Hash
    > doesn't preserve order.
    > Do the following:
    >
    > pi_array_sorted = [
    > ['general_event_types', [GeneralEventType1,
    > GeneralEventType2, ..]],
    > ['prices', [Price1, Price2, ..]],
    > ['specific_event_types', [SpecificEventType1,
    > SpecificEventType2, ..]],
    > ['general_event_types', [Teacher1, Teacher2, ..]]
    > ]
    >
    > pi_array_sorted.each do |key,value|
    > # do stuff here
    > end
    >
    > Cheers


    Hi Rodrigo,

    sorry, maybe the code was confusing, I just wanted to visualize the
    result array I like to get after sorting. So the "pi_array_sorted ="
    shouldn't be an assignement and I used the wrong brakets. Thanks all
    for your comments, but unfortunately concerning
    the sorting issue I'm not a single step further.

    Cheers,
    Nico

    --
    Posted via http://www.ruby-forum.com/.
     
    Nico Ritsche, Jan 29, 2008
    #17
  18. Nathan Viswa

    Ilan Berci Guest

    Nico Ritsche wrote:
    > Rodrigo Kochenburger wrote:
    >>> pi_array_sorted =
    >>> { 'general_event_types', �[GeneralEventType1, GeneralEventType2, ..],
    >>> � 'prices', � � � � � � � [Price1, Price2, ..],
    >>> � 'specific_event_types', [SpecificEventType1, SpecificEventType2, ..],
    >>> � 'general_event_types', �[Teacher1, Teacher2, ..] }
    >>>


    > Nico


    Nico,

    We can help but you must strive to explain what you want clearly and
    legibly.. For the pi_array_sorted, it appears that you want to convert a
    hash of arrays into an array of arrays where the second arrays is
    sorted.

    Here is a solution that sorts the nested arrays and then the initial
    array

    irb(main):002:0> a = {1=>[3,7,1,7], 2=>[3,7,1,1],3=>[3,2,2,9]}
    => {1=>[3, 7, 1, 7], 2=>[3, 7, 1, 1], 3=>[3, 2, 2, 9]}
    irb(main):003:0> a.each {|b,c| c.sort!}
    => {1=>[1, 3, 7, 7], 2=>[1, 1, 3, 7], 3=>[2, 2, 3, 9]}
    irb(main):004:0> a.sort
    => [[1, [1, 3, 7, 7]], [2, [1, 1, 3, 7]], [3, [2, 2, 3, 9]]]

    hth

    If it doesn't then write the code EXACTLY as you have it.. and then the
    exact output that you desire and we will code it for you.. The code that
    you submitted is barely readable and leaves a lot open to
    interpretation.

    ilan
    --
    Posted via http://www.ruby-forum.com/.
     
    Ilan Berci, Jan 29, 2008
    #18
  19. Nathan Viswa

    Nico Ritsche Guest

    Ilan Berci wrote:
    > Nico Ritsche wrote:
    >> Rodrigo Kochenburger wrote:
    >>>> pi_array_sorted =
    >>>> { 'general_event_types', �[GeneralEventType1, GeneralEventType2, ..],
    >>>> � 'prices', � � � � � � � [Price1, Price2, ..],
    >>>> � 'specific_event_types', [SpecificEventType1, SpecificEventType2, ..],
    >>>> � 'general_event_types', �[Teacher1, Teacher2, ..] }
    >>>>

    >
    >> Nico

    >
    > Nico,
    >
    > We can help but you must strive to explain what you want clearly and
    > legibly.. For the pi_array_sorted, it appears that you want to convert a
    > hash of arrays into an array of arrays where the second arrays is
    > sorted.
    >
    > Here is a solution that sorts the nested arrays and then the initial
    > array
    >
    > irb(main):002:0> a = {1=>[3,7,1,7], 2=>[3,7,1,1],3=>[3,2,2,9]}
    > => {1=>[3, 7, 1, 7], 2=>[3, 7, 1, 1], 3=>[3, 2, 2, 9]}
    > irb(main):003:0> a.each {|b,c| c.sort!}
    > => {1=>[1, 3, 7, 7], 2=>[1, 1, 3, 7], 3=>[2, 2, 3, 9]}
    > irb(main):004:0> a.sort
    > => [[1, [1, 3, 7, 7]], [2, [1, 1, 3, 7]], [3, [2, 2, 3, 9]]]
    >
    > hth
    >
    > If it doesn't then write the code EXACTLY as you have it.. and then the
    > exact output that you desire and we will code it for you.. The code that
    > you submitted is barely readable and leaves a lot open to
    > interpretation.
    >
    > ilan


    Hi Ilan,

    actually I supplied my exact code already.

    So here again, my exact code that doesn't work:

    @parent_items = {}

    @parent_items['teachers'] = Teacher.find:)all)
    @parent_items['prices'] = Price.find:)all)
    @parent_items['general_event_types'] = GeneralEventType.find:)all,
    :conditions => "language_parent_id = id")
    @parent_items['specific_event_types'] = SpecificEventType.find:)all,
    :conditions => "language_parent_id = id")

    pi_array_sorted = @parent_items.to_a.sort

    So what I'm doing here is building a hash containing arrays of rails
    active record objects. So for example @parent_items['teachers'] is an
    array of Teacher records. Then I call the hashs's sort method. After
    doing this I expect pi_array_sorted to be a nested array, sorted by key,
    as the documentation of Hash.sort suggests ("Converts hsh to a nested
    array of [ key, value ] arrays and sorts it, using Array#sort."). So the
    result for the above code should be this nested array:


    [ 'general_event_types', [GeneralEventType1, GeneralEventType2, ..],
    'prices', [Price1, Price2, ..],
    'specific_event_types', [SpecificEventType1, SpecificEventType2, ..],
    'teachers', [Teacher1, Teacher2, ..] ]

    But this is not what I get. The keys in the resulting array still have
    an arbitrary order, the exact same order as if I don't call .sort at
    all.

    Nico

    --
    Posted via http://www.ruby-forum.com/.
     
    Nico Ritsche, Jan 30, 2008
    #19
  20. Nathan Viswa

    Gary Wright Guest

    On Jan 30, 2008, at 1:39 AM, Nico Ritsche wrote:
    >
    >
    > [ 'general_event_types', [GeneralEventType1, GeneralEventType2, ..],
    > 'prices', [Price1, Price2, ..],
    > 'specific_event_types', [SpecificEventType1,
    > SpecificEventType2, ..],
    > 'teachers', [Teacher1, Teacher2, ..] ]
    >
    > But this is not what I get. The keys in the resulting array still have
    > an arbitrary order, the exact same order as if I don't call .sort at
    > all.


    Can you cut, paste, and post the snippit of code you are using to
    display your incorrect results?
     
    Gary Wright, Jan 30, 2008
    #20
    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.
Similar Threads
  1. Replies:
    2
    Views:
    1,465
    James Kanze
    Jul 6, 2010
  2. rp
    Replies:
    1
    Views:
    557
    red floyd
    Nov 10, 2011
  3. Williams, Chris
    Replies:
    3
    Views:
    111
    Florian Gross
    Dec 13, 2004
  4. Srijayanth Sridhar
    Replies:
    19
    Views:
    644
    David A. Black
    Jul 2, 2008
  5. IanW
    Replies:
    3
    Views:
    135
    Ian Stuart
    Dec 14, 2005
Loading...

Share This Page