SlowBucket
SlowBucket

Reputation: 167

Sorting using custom value system in ruby

I have an application that dynamically creates a drop-down menu based on certain values in the database. Often the drop-down values are just in the order they come up but I would like to put them in a certain order.

An example of my value system:

Newbie = 0
Amateur = 1
Skilled = 2
Pro = 3
GrandMaster = 4

How would I take the data above and use it to sort an array full of those values (Newbie etc). I've thought about creating a hash of the values but even then I still am not sure how to apply that to the sort method.

Any help would be appreciated.

Upvotes: 0

Views: 613

Answers (6)

SlowBucket
SlowBucket

Reputation: 167

Due to my poorly explained question the others trying to answer my question didn't really get a chance but using their help I did manage to figure out my problem.

ex_array = ["GrandMaster", "Newbie", "Pro", "Skilled", "Amateur"] 
value_sys = {:Newbie=>0, :Amateur=>1, :Skilled=>2, :Pro=>3, :GrandMaster=>4}

ex_array.sort { |a,b| value_sys[a.to_sym] <=> value_sys[b.to_sym]
=> ["Newbie", "Amateur", "Skilled","Pro", "GrandMaster"]

Thanks for the help guys. Much appreciated.

Upvotes: 0

Mark Swardstrom
Mark Swardstrom

Reputation: 18080

An alternate to @padde. I prefer to avoid default scopes.

class Level < ActiveRecord::Base
  #### attributes
  # id (integer)
  # name (string)
  # value (integer)
end

In the view

<%= f.select("level", Level.order(:value).map{|l| [l.name, l.value] } %>

Upvotes: 0

Arie Xiao
Arie Xiao

Reputation: 14082

  1. Parse your value system for further use:

    values = <<EOF
    Newbie = 0
    Amateur = 1
    Skilled = 2
    Pro = 3
    GrandMaster = 4
    EOF
    
    value_map = Hash[values.split("\n").map{|v| v.split(/\s*=\s*/)}.map{|v| [v[0], v[1].to_i]}]
    #=> {"Newbie"=>0, "Amateur"=>1, "Skilled"=>2, "Pro"=>3, "GrandMaster"=>4}
    
  2. Assign the array values a weight according to value_map to transform the array into a new one, sort according to the weight, and then transform the new array back.

    # here I created a sample array
    array = value_map.keys.shuffle
    #=> ["Newbie", "Pro", "Skilled", "Amateur", "GrandMaster"]
    
    # transform and sort
    sorted = array.map{|v| [v, value_map[v] || 0xFFFF]}.sort_by{|v| v[1]}.map{|v| v[0]}
    #=> ["Newbie", "Amateur", "Skilled", "Pro", "GrandMaster"]
    

    Or you can bypass the transform step and just use the sort_by method:

    sorted = array.sort_by{|v| value_map[v] || 0xFFFF}
    

Upvotes: -2

Patrick Oscity
Patrick Oscity

Reputation: 54684

Suppose you have a Level model that has a sort_id identifying the displayed order and a name holding the displayed name. I recommend using default_scope to set the default order for that model because it is likely that you always want to sort Level records this way:

class Level < ActiveRecord::Base
  #### attributes
  # id (integer)
  # name (string)
  # sort_id (integer)

  default_scope order('sort_id ASC')

  # rest of model...
end

Then, the only thing you have to do in your view to display a picklist is

<%= f.select("level", Level.pluck(:name)) %>

Upvotes: 0

dirtydexter
dirtydexter

Reputation: 1073

You can sort this array just by using the usual sorting the sorting won't be done by name it will be done by value. and if these are not integer objects and are some user defined class then sorting based on a particular attribute can be achieved very efficiently by

lst.sort_by &:first

where first is the attribute of the object.

Upvotes: 2

Dmytro
Dmytro

Reputation: 149

Sort has by value:

hash = {:Newbie=>0, :Amateur=>1, :Skilled=>2, :Pro=>3}
> hash.sort { hash{a} <=> hash{b} }
=> [[:Newbie, 0], [:Amateur, 1], [:Skilled, 2], [:Pro, 3]] 

Or use Ruby Hash#sort_by method:

hash.sort_by { |k,v| v }

Upvotes: 1

Related Questions