2009-05-24 19 views
3

Mes excuses si cela a été répondu avant ou est évident ... fait quelques recherches ici et sur le Goog et n'a pas pu trouver une réponse.Trier les objets par des valeurs booléennes dans Ruby

Je cherche à trier un tableau de fournisseurs par prix et si elles sont un preferred_provider? (Vrai ou faux)

Par exemple, dans array p of Providers ...

p1.price == 1, p1.preferred_provider? == false 
p2.price == 2, p2.preferred_provider? == true 
p2.price == 3, p3.preferred_provider? == true 

Je voudrais p.sort_by et obtenir:

[p2 p3 p1] 

IAW

p.sort_by {|x| x.preferred_provider?, x.price } 

ne le fait pas travailler et obtient ...

undefined method `<=>' for false:FalseClass 

Des suggestions sur de meilleures façons d'aborder ce problème?

+0

En fait, vous aviez presque: p.sort_by {| x | [x.preferred_provider? ? 0: 1, x.prix]}. –

+0

Ah ... sympa. candidat refactoring. Merci. –

Répondre

7

La plupart des langues fournissent des fonctions de tri qui acceptent comparators pour ce genre de chose. Dans Ruby, c'est juste array.sort:

p.sort {|a, b| if (a.preferred_provider? == b.preferred_provider? 
       then a.price <=> b.price 
       elsif a.preferred_provider? 
        1 
       else -1 
     } 
+0

Cette logique ne retourne pas l'ordre correct, mais elle m'a mis sur le bon chemin en utilisant un .preferred_provider? == b.preferred_provider? et inversant 1 et -1. merci –

+1

Oups, bien sûr, vous voudrez utiliser == là (corrigé maintenant). Pour élaborer un peu, la fermeture doit renvoyer un nombre positif si a vient après b, un nombre négatif si un vient avant b, et 0 s'ils sont égaux pour le tri. De cette façon, une implémentation facile pour trier les valeurs numériques est {| a, b | un B}. –

3

Vous pouvez définir un <=> sur la classe Provider pour faire ce que vous voulez, puis trier en utilisant la méthode Array.sort (plutôt que Enumerable.sort_by). Voici une définition de <=> que je fouetté:

class Provider 
    def <=>(other) 
    if preferred_provider? 
     if other.preferred_provider? 
     @price <=> other.price 
     else 
     1 
     end 
    else 
     if other.preferred_provider? 
     -1 
     else 
     @price <=> other.price 
     end 
    end 
    end 
end 

Ensuite, si vous avez votre choix p, vous pouvez simplement faire p_sorted = p.sort.

(Notez que je ne l'ai pas testé ce code, donc il peut y avoir quelques erreurs, mais je pense qu'il sert à démontrer l'idée.)

+0

Cela fonctionnerait mais l'autre solution était plus appropriée pour mon problème pour des raisons que je n'ai pas indiquées dans la question originale. Merci ... très apprécié. –

Questions connexes