我有一个数组“大小”,如下所示:
[#<OPTIONVALUE ID: 5, NAME: "M">,
#<OPTIONVALUE ID: 6, NAME: "M/L">,
#<OPTIONVALUE ID: 7, NAME: "XS/S">]
考虑属性NAME的值。数组排序:M,M / L,XS / S.
但排序顺序应如下所示:
@sizes_sort_order = ["XS", "XS/S", "S", "S/M", "M", "M/L", "L", "L/XL", "XL"]
应用于前一个数组,元素的顺序应如下所示:
[#<SPREE::OPTIONVALUE ID: 7, NAME: "XS/S">,
#<SPREE::OPTIONVALUE ID: 5, NAME: "M">,
#<SPREE::OPTIONVALUE ID: 6, NAME: "M/L">]
def sizes
@sizes ||= grouped_option_values_by_option_type[Spree::OptionType.find_by!(name: 'size')]
@sizes_sort_order = ["XS", "XS/S", "S", "S/M", "M", "M/L", "L", "L/XL", "XL"]
@sizes.map { # sort after @size_sort_order }
end
如何在@sizes_sort_order之后将数组中的元素排序?
答案 0 :(得分:3)
您可以使用Enumerable#sort_by
my_array.sort_by {|x| @sizes_sort_order.index(x.name) }
答案 1 :(得分:2)
您可以包含Comparable
模块以获得对象的自然排序。
http://ruby-doc.org/core-2.2.3/Comparable.html
Comparable mixin由可以对其对象进行排序的类使用。 该类必须定义&lt; =&gt;运算符,用于比较接收器 对另一个对象,返回-1,0或+1取决于是否 接收器小于,等于或大于另一个物体。
class Size
include Comparable
SIZES = ["XS", "XS/S", "S", "S/M", "M", "M/L", "L", "L/XL", "XL"]
attr_reader :name
def initialize(id, name)
@id = id
@name = name
end
def <=>(b)
SIZES.index(name) <=> SIZES.index(b.name)
end
end
a = Size.new(5, 'M')
b = Size.new(6, 'M/L')
c = Size.new(7, 'XS/S')
print [a, b, c].sort
[#<Size:0x007f8e910458e0 @id=7, @name="XS/S">, #<Size:0x007f8e910459a8 @id=5, @name="M">, #<Size:0x007f8e91045930 @id=6, @name="M/L">]
答案 2 :(得分:1)
这种方法涉及的步骤多于使用sort
或sort_by
的方法,但对于较大的数组,它可能更快,因为不涉及排序 - 这是相对昂贵的。
<强>代码强>
def reorder_by_size(instances, size_order)
instances.each_with_object({}) { |inst, h| h.update(inst.name=>inst) }.
values_at(*(size_order & (instances.map { |s| s.name })))
end
示例强>
首先让我们创建一个
的实例数组class Sizes
attr_reader :name
def initialize(id, name)
@id = id
@name = name
end
end
像这样:
instances = [Sizes.new(5,'M'), Sizes.new(6,'M/L'), Sizes.new(7, 'XS/S')]
#=> [#<Sizes:0x007fa66a955ac0 @id=5, @name="M">,
# #<Sizes:0x007fa66a955a70 @id=6, @name="M/L">,
# #<Sizes:0x007fa66a955a20 @id=7, @name="XS/S">]
然后
reorder_by_size(instances, @sizes_sort_order)
#=> [#<Sizes:0x007fa66a01dfc0 @id=7, @name="XS/S">,
# #<Sizes:0x007fa66a86fdb8 @id=5, @name="M">,
# #<Sizes:0x007fa66a8404f0 @id=6, @name="M/L">]
<强>解释强>
对于示例中定义的instances
,首先按所需顺序创建一个大小数组:
names = @sizes_sort_order & (instances.map { |s| s.name })
#=> ["XS/S", "M", "M/L"]
重要:Array#&状态的文档,“订单将从原始数组中保留。”
现在我们可以在不进行排序的情况下创建所需的重新排序,方法是创建一个带有键大小和值的实例的哈希,然后使用Hash#values_at以所需的顺序提取实例。
instances.each_with_object({}) { |inst, h|
h.update(inst.name=>inst) }.values_at(*names)
#=> [#<Sizes:0x007fa66a01dfc0 @id=7, @name="XS/S">,
# #<Sizes:0x007fa66a86fdb8 @id=5, @name="M">,
# #<Sizes:0x007fa66a8404f0 @id=6, @name="M/L">]
最后一项操作涉及以下两个步骤。
h = instances.each_with_object({}) { |inst, h| h.update(inst.name=>inst) }
#=> {"M" => #<Sizes:0x007fa66a955ac0 @id=5, @name="M">,
# "M/L" => #<Sizes:0x007fa66a955a70 @id=6, @name="M/L">,
# "XS/S" => #<Sizes:0x007fa66a955a20 @id=7, @name="XS/S">}
h.values_at(*names)
#=> h.values_at(*["XS/S", "M", "M/L"])
#=> h.values_at("XS/S", "M", "M/L")
#=> [#<Sizes:0x007fa66a955a20 @id=7, @name="XS/S">,
# #<Sizes:0x007fa66a955ac0 @id=5, @name="M">,
# #<Sizes:0x007fa66a955a70 @id=6, @name="M/L">]