如何在Ruby中对2个字符串属性进行有效排序,其中任何一个属性都可能为零?

时间:2013-05-13 22:32:23

标签: ruby performance sorting

class Foo
  attr_reader :size, :color

  def <=>
    ...


foo1 = Foo.new( size: 'large', color: 'blue'  )
foo2 = Foo.new( size: 'small'                 )
foo3 = Foo.new( color: 'green'                )
foo4 = Foo.new( size: 'small', color: 'red'   )
  ...

尺寸订购小,零,中,大,超大。颜色为绿色,零色,蓝色,红色。

如何根据尺寸,然后按颜色有效排序?

3 个答案:

答案 0 :(得分:2)

首先我明确声明订单:

@@size_order = {
    'small' => 1, 
    'medium' => 2, 
    'large' => 3, 
    'super-sized' => 4
}

@@color_order = {
    'green' => 1,
    'blue' => 2,
    'red' => 3
}

然后您可以按照以下方式确定<=>方法:

def <=> ( o )
    if (@size == o.size)
        if (@color == o.color) 
            return 0
        else
            return (@@color_order[@color] > @@color_order[o.color]) ? 1 : -1
        end
    else
        return (@@size_order[@size] > @@size_order[o.size]) ? 1 : -1
    end
end

这是a test example

但是,使用两个类FooColorSize子类化为{em>更好(更多OOP)并定义<=>对于他们每个人。

答案 1 :(得分:2)

class Foo
  attr_reader :size, :color
  VALID_COLORS = ["small",nil,"medium","large","super-sized"]
  VALID_SIZES  = ["green", nil, "blue", "red" ]

  def size_pos
    VALID_COLORS.index(size) || -1
  end

  def color_pos
    VALID_SIZES.index(color) || -1
  end

  def initialize(opts={})
    @size=opts[:size]
    @color=opts[:color]
  end

  def <=>(other)
    [size_pos,color_pos] <=> [other.size_pos, other.color_pos]
  end
end

foo1 = Foo.new( size: 'large', color: 'blue'  )
foo2 = Foo.new( size: 'small'                 )
foo3 = Foo.new( color: 'green'                )
foo4 = Foo.new( size: 'small', color: 'red'   )

[foo1,foo2,foo3,foo4].sort

#[#<Foo:0x000000020848d0 @size="small", @color=nil>, 
 #<Foo:0x00000002065700 @size="small", @color="red">, 
 #<Foo:0x00000002074868 @size=nil, @color="green">, 
 #<Foo:0x0000000208da98 @size="large", @color="blue"> ]

您可以通过将位置提取到类变量哈希或常量而不是每次调用索引来提高性能。

答案 2 :(得分:0)

假设'foos'是foo对象的集合:

foos.sort_by {|f| [ f.size || '', f.color || '' ]}

这可能比使用sort或定义&lt; =&gt;更有效。如果要调整排序顺序,则可以在属性为nil时使用空字符串以外的其他内容。为了提高灵活性,您可以执行以下操作:

def sort_by_size
  foos.sort_by {|f| [ f.size || '', f.color || '' ]}
end

def sort_by_color
  foos.sort_by {|f| [ f.color|| '', f.size|| '' ]}
end