2016-07-27 15 views
0

後、私は次のようになり、アレイ「サイズ」を持っています。配列はソートされます:M、M/L、XS /​​ S。ルビー:</p> <pre><code>[#<OPTIONVALUE ID: 5, NAME: "M">, #<OPTIONVALUE ID: 6, NAME: "M/L">, #<OPTIONVALUE ID: 7, NAME: "XS/S">] </code></pre> <p>属性名の値を考えてみましょう:オブジェクトの配列を並べ替えるには名前プロパティの配列

しかし、ソート順は次のようになります。

[#<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 = ["XS", "XS/S", "S", "S/M", "M", "M/L", "L", "L/XL", "XL"] 

は、要素の順序は次のようになります。元の配列に適用@sizes_sort_orderの後にソートされた配列内にありますか?

+1

[ '可算#のsort_by'](http://ruby-doc.org/core-2.2.0/Enumerable.html#method-i-sort_by)を見 –

答えて

3

あなたは、あなたがオブジェクトのための自然の並べ替えを取得するためにComparableモジュールを含めることができEnumerable#sort_by

my_array.sort_by {|x| @sizes_sort_order.index(x.name) } 
2

を使用することができます。

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

このアプローチは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 

まず者がそうのような

​​

のインスタンスの配列を作成してみましょう:

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">] 
instancesについて

そして

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

説明

例えば定義されたように、第1の所望の順序でのサイズのアレイを作成する:

names = @sizes_sort_order & (instances.map { |s| s.name }) 
    #=> ["XS/S", "M", "M/L"] 

重要:DOC 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">] 

最後の操作には、次の2つの手順があります。

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

関連する問題

 関連する問題