Comment puis-je trier par plusieurs conditions avec différentes commandes?

StackOverflow https://stackoverflow.com/questions/73032

  •  09-06-2019
  •  | 
  •  

Question

Je voudrais vraiment pouvoir gérer ça sans utiliser la technique du singe, mais je n'ai pas encore trouvé d'autre option.

J'ai un tableau (en Ruby) que je dois trier selon plusieurs conditions. Je sais comment utiliser la méthode de tri et j'ai utilisé l'astuce sur le tri en utilisant un tableau d'options pour trier selon plusieurs conditions. Cependant, dans ce cas, j'ai besoin de la première condition pour trier par ordre croissant et de la seconde pour trier par ordre décroissant. Par exemple:

ordered_list = [[1, 2], [1, 1], [2, 1]]

Des suggestions?

Edit: Je viens de me rendre compte que je devrais mentionner que je ne peux pas facilement comparer les première et seconde valeurs (je travaille actuellement avec des attributs d’objet). Donc, pour un exemple simple, cela ressemble plus à:

ordered_list = [[1, "b"], [1, "a"], [2, "a"]]
Était-ce utile?

La solution

Que diriez-vous de:


ordered_list = [[1, "b"], [1, "a"], [2, "a"]]
ordered_list.sort! do |a,b|
  [a[0],b[1]] <=> [b[0], a[1]]
end

Autres conseils

Je passais mon temps à cauchemarder pour essayer de trouver comment trier de manière inverse un attribut spécifique, mais normalement les deux autres. Juste une note sur le tri pour ceux qui viennent après cela et qui sont déroutés par le | a, b | syntaxe de bloc. Vous ne pouvez pas utiliser le style de bloc {|a,b| a.blah <=> b.blah} avec sort_by! ou sort_by. Il doit être utilisé avec sort! ou sort. De même, comme indiqué précédemment par les autres afficheurs, permutez a et b sur l'opérateur de comparaison <=> pour inverser l'ordre de tri. Comme ceci:

Pour trier par blah et craw normalement, mais par bleu dans l'ordre inverse, procédez comme suit:

something.sort!{|a,b| [a.blah, b.bleu, a.craw] <=> [b.blah, a.bleu, b.craw]}

Il est également possible d’utiliser le signe - avec a.craw ou <=> pour effectuer un tri inversé sur les chiffres (pour autant que je sache, cela ne fonctionne que sur les chiffres, n’essayez donc pas avec des chaînes c'est juste des erreurs et tue la page).

Supposons que <=> est un entier. Par exemple:

something.sort_by!{|a| [a.blah, -a.craw, a.bleu]}

J'ai eu le même problème de base et je l'ai résolu en ajoutant ceci:

class Inverter
  attr_reader :o

  def initialize(o)
    @o = o
  end

  def <=>(other)
    if @o.is && other.o.is
      -(@o <=> other.o)
    else
      @o <=> other.o
    end
  end
end

C’est un wrapper qui inverse simplement le < = > fonction, qui vous permet ensuite de faire des choses comme ceci:

your_objects.sort_by {|y| [y.prop1,Inverter.new(y.prop2)]}

Enumerable#multisort est une solution générique qui peut être appliquée à des tableaux de toute taille , pas uniquement à ceux comportant 2 éléments. Les arguments sont des booléens qui indiquent si un champ spécifique doit être trié par ordre croissant ou décroissant (utilisation ci-dessous):

items = [
  [3, "Britney"],
  [1, "Corin"],
  [2, "Cody"],
  [5, "Adam"],
  [1, "Sally"],
  [2, "Zack"],
  [5, "Betty"]
]

module Enumerable
  def multisort(*args)
    sort do |a, b|
      i, res = -1, 0
      res = a[i] <=> b[i] until !res.zero? or (i+=1) == a.size
      args[i] == false ? -res : res
    end
  end
end

items.multisort(true, false)
# => [[1, "Sally"], [1, "Corin"], [2, "Zack"], [2, "Cody"], [3, "Britney"], [5, "Betty"], [5, "Adam"]]
items.multisort(false, true)
# => [[5, "Adam"], [5, "Betty"], [3, "Britney"], [2, "Cody"], [2, "Zack"], [1, "Corin"], [1, "Sally"]]

J'utilise la recette de Glenn depuis un bon moment maintenant. Fatigué de copier le code d'un projet à l'autre, j'ai décidé d'en faire un joyau:

http://github.com/dadooda/invert

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top