1

I'm trying to sort an array of hashes based on the given key-value, and will return that value on top of the array first, then preceded by the remaining data.

Example would be:

students = [{name: "John Doe", age: 16, adviser: "Mrs. Robinson"},
            {name: "John Smith", age: 18, adviser: "Mrs. Williams"},
            {name: "Michael Rodriguez", age: 17, adviser: "Mr. Lee"}]

def sort_by_adviser(data, name)
  ...
end

> sort_by_adviser(students, "Mr. Lee")
=> [{name: "Michael Rodriguez", age: 17, adviser: "Mr. Lee"},
    {name: "John Doe", age: 16, adviser: "Mrs. Robinson"},
    {name: "John Smith", age: 18, adviser: "Mrs. Williams"}]

> sort_by_adviser(students, "Mrs. Williams")
=> [{name: "John Smith", age: 18, adviser: "Mrs. Williams"},
    {name: "Michael Rodriguez", age: 17, adviser: "Mr. Lee"},
    {name: "John Doe", age: 16, adviser: "Mrs. Robinson"}]

Here the output brings the adviser's name on top of the list, then preceded by other hashes in the array.

> sort_by_keyvalue(data, "Z")
=> [{letter: 'Z'},
    {letter: 'A'},
         .
         .
         .
    {letter: 'Y'}]

> sort_by_keyvalue(data, 5)
=> [{number: 5, value: 'value1'},
    {number: 5, value: 'value2'},
    {number: 5, value: 'value3'},
    {number: 9, value: 'value1'},
    {number: 9, value: 'value2'},
    {number: 8, value: 'value1'},
    {number: 8, value: 'value2'},
    {number: 7, value: 'value1'},
    {number: 6, value: 'value1'},
    {number: 4, value: 'value1'},
    {number: 3, value: 'value1'},
    {number: 2, value: 'value1'},
    {number: 1, value: 'value1'},
    {number: 1, value: 'value2'},
    {number: 0, value: 'value1'}]

Anyone knows how to do it?

2
  • do you want to do any sorting, or just to move the matched one to the first place? Commented Aug 3, 2012 at 19:39
  • move the matched on in the first place, then do a sort_by { |k,v| k[:key] } to sort the remaining hash in the array. Commented Aug 3, 2012 at 19:48

5 Answers 5

3

Another implemention :)

def sort_by_adviser(data, name)
    data.each_with_index do |hash,index|
      if hash[:adviser]==name
         data.delete_at index #delete from array
         data.unshift hash
         break
      end
    end
   data
end

 > sort_by_adviser(students, "Mr. Lee")  
 #=> [{:name=>"Michael Rodriguez", :age=>17, :adviser=>"Mr. Lee"}, {:name=>"John Doe", :age=>16, :adviser=>"Mrs. Robinson"}, {:name=>"John Smith", :age=>18, :adviser=>"Mrs. Williams"}] 
Sign up to request clarification or add additional context in comments.

Comments

2
def creamy_sort(key, value, arr)
  top, bottom = arr.partition{|e| e[key] == value }
  top.concat(bottom.sort{|a,b| b[key] <=> a[key]})
end

creamy_sort(:adviser, "Mr. Lee", students)

Comments

1

You can do that:

def sort_by_adviser(data, name)
  data = data.sort{|x,y|x[:adviser] <=> y[:adviser]}
  i = data.index{|h|h[:adviser] = name}
  h = data.delete_at i
  data.unshift h
end

Comments

1

I have this solution:

students = [{name: "John Doe", age: 16, adviser: "Mrs. Robinson"},
            {name: "John Smith", age: 18, adviser: "Mrs. Williams"},
            {name: "Michael Rodriguez", age: 17, adviser: "Mr. Lee"}]

def sort_by_adviser(data, *name)
  data.sort_by{| entry |    
    [ 
      name.index(entry[:adviser]) || 999,
      entry[:age], entry[:name] #2nd sort criteria
    ]
  }
end

p sort_by_adviser(students, "Mr. Lee")
#[{:name=>"Michael Rodriguez", :age=>17, :adviser=>"Mr. Lee"}, {:name=>"John Doe", :age=>16, :adviser=>"Mrs. Robinson"}, {:name=>"John Smith", :age=>18, :adviser=>"Mrs. Williams"}]

p sort_by_adviser(students, "Mrs. Williams")
# [{:name=>"John Smith", :age=>18, :adviser=>"Mrs. Williams"}, {:name=>"John Doe", :age=>16, :adviser=>"Mrs. Robinson"}, {:name=>"Michael Rodriguez", :age=>17, :adviser=>"Mr. Lee"}]

I didn't understand, what's the sorting of the remaining entry.

You wrote: then preceded by the remaining data. What's tho order criteria of the hash?

I selected age, followed by name. But you may adapt it for your need.

Comments

1
def weird_sort(array, key, value)
  return array.sort_by{|d| 2 <=> (d[key] == value).object_id}
end

This is based on the fact that true.object_id equals 2 in ruby. Kind of a weird solution that's why it's a weird_sort :p It also messes around the other value ordering ... so it only guarantees you that values that are equal go on top!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.