2013-02-11 14 views
10

products bir galeriyi görüntülemek istiyorum. Burada hem satılık hem de satılık olmayan ürünleri dahil ediyorum. Sadece listenin ön tarafında görünecek olan products numarasının ve satış için bulunmayan nesnelerin listenin sonunda görünmesini istiyorum.Bir nesnenin listesini, bir nesnenin bir yönteme verdiği cevaba bağlı olarak sıralamak mümkün mü?

available_products = [] 
sold_products = [] 
@products.each do |product| 
    if product.on_sale? 
    available_products << product 
    else 
    sold_products << product 
    end 
end 

:

bana bunu gerçekleştirmek için kolay bir yolu daha sonra onları (?? On_sale nesnelerin bir listesi ve on_sale değil nesnelerin bir listesini) birleştirme, iki listeyi yapmaktır. . . Ama benim mevcut app yapısına yapmak, bu benim kodda bir tuhaflık nedeniyle aşırı miktarda refactoring gerektirecektir (Ben sayfalama kaybettim ve ben refactor değil). Mevcut nesne listesini sıralamak için product modelinin on_sale? bir boole değeri döndüren yöntemi daha kolay olurdu.

Varolan bir listeyi daha zarif bir şekilde yineleyebilir ve bu doğru veya yanlış değerlere göre sıralayabilir miyiz? Sadece soruyorum çünkü bu çerçeve/dil içinde saklı olduğunun farkında değilim ve çalışmamın benden önce yapılıp yapılmadığını bilmek istiyorum.

cevap

11

Elbette. İdeal biz sort_by! kullanarak böyle bir şey yapacağını:

@products.sort_by! {|product| product.on_sale?} 

veya snazzier

@products.sort_by!(&:on_sale?) 

ama ne yazık ki, <=> (Why doesn't sort or the spaceship (flying saucer) operator (<=>) work on booleans in Ruby? bakınız) boolelerde için çalışmaz ve sort_by boolean için çalışmıyor değerler, bu yüzden bu hüner kullanmaya gerek (teşekkürler rohit89!)

@products.sort_by! {|product| product.on_sale? ? 0 : 1} 

Eğer meraklı olmak istiyorsanız, sort yöntemi bir blok alır ve bu bloğun içinde, dönüşüm ve çoklu tuşlar dahil olmak üzere istediğiniz mantığı kullanabilirsiniz.

@products.sort! do |a,b| 
    a_value = a.on_sale? ? 0 : 1 
    b_value = b.on_sale? ? 0 : 1 
    a_value <=> b_value 
end 

veya bu:

@products.sort! do |a,b| 
    b.on_sale?.to_s <=> a.on_sale?.to_s 
end 

(eğer "true" değerleri "false" önce gelmek istiyorum bir de daha önce b koyarak) ya da ikincil bir çeşit varsa:

Böyle bir şey deneyin
@products.sort! do |a,b| 
    if a.on_sale? != b.on_sale? 
    b.on_sale?.to_s <=> a.on_sale?.to_s 
    else 
    a.name <=> b.name 
    end 
end 

sort döndürdüğünü unutmayın genellikle daha temiz, daha az hataya açık bir çözüm olan ew koleksiyonu, ancak sort!, orijinal koleksiyonun içeriğini değiştirdiğini söylediniz.

+0

harika görünüyor! Ama benim özel kodumla sorun yaşıyorum, belki bana yardım edebilirsin. Tek liner kullanırsam, falseClass ile karşılaştırılamazsa aşağıdaki hatayı alırsam, ve bahsettiğin ilk kodu kullanırsam, [MyModule] :: Ürünü [MyModule] ile karşılaştırırdım :: Ürün başarısız oldu '. Bunun neden başarısız olabileceğinden emin değilim. – Ecnalyr

+0

Bazı notlar: 1) Her zaman mümkün olduğunda 'sort_by' '' sort' '' kullanılmalıdır (daha açıklayıcı, daha özlü, daha verimli). Yukarıda gösterilen tüm parçacıklarda kullanmak mümkündür. 2) Tahribatsız “Numaralandırılabilir # sort_by” ile bağlantı kurmam tercih edilebilir, mümkün olduğunda yerinde güncellemelerden kaçınılmalıdır. 3) '@ product.sort_by (&: on_sale?)'. – tokland

+0

'<=> 'gibi görünüyor Booleanlar için doğru çalışmıyor (ruby-1.9.3-p327 içinde). Şimdi bakıyorum ... Evet, http://grosser.it/2010/07/30/ruby-true-false-comparison-with/ daha önceki bir sürüm için onayladı – AlexChaffee

4

@products.sort_by {|product| product.on_sale? ? 0 : 1}

Bu benim boolelerde dayalı sıralayabilirsiniz zorunda kaldı ben bunu yaptı.

4

gerek yok sıralamak için:

products_grouped = @products.partition(&:on_sale?).flatten(1) 
0

Artan ve azalan arası değişen yapılabilir "yanlış" ve "gerçek"

Products.sort_by {|product| product.on_sale? == true ? "false" : "true" } 
İlgili konular