2016-07-27 21 views
0

我有一個數組「大小」,看起來像這樣:紅寶石:名稱屬性數組後的對象排序數組

[#<OPTIONVALUE ID: 5, NAME: "M">, 
#<OPTIONVALUE ID: 6, NAME: "M/L">, 
#<OPTIONVALUE ID: 7, NAME: "XS/S">] 

考慮屬性名稱的值。數組排序: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之後排序的數組中?

+1

看['可枚舉#sort_by'(http://ruby-doc.org/core-2.2.0/Enumerable.html#method-i-sort_by) –

回答

2

可以包括Comparable模塊獲取的對象的自然排序。

http://ruby-doc.org/core-2.2.3/Comparable.html

可比混入由類其對象可以是有序的使用。 該類必須定義< =>運算符,該運算符將接收方 與另一個對象進行比較,返回-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">] 
1

這種方法涉及比採用sortsort_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 

首先,讓我們創建的

​​

實例的數組像這樣:

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">] 
+0

哇,非常感謝卡里!對於這種情況,我堅持sort_by解決方案,但對於更大的陣列,我會選擇你的。非常好的解釋方式。 – StandardNerd