2 votes

Comment éliminer les sorties non pertinentes de mon code ?

Voici mon code jusqu'à présent :

class Integer
  def atm
    money =  %w[e500 e200 e100 e50 e20 e10 e5]
    return '' if self == 0    
    money.each do |m|        
      value = m.split('e').last.to_i    
      next if self.to_f / value < 1.0    
      anm = self / value
      erg = ("e" + value.to_s)
      return money << {erg => anm}, (self-anm*value).atm
      end
  end
end

puts 140.atm

Il donne ce résultat :

e500 e200 e100 e50 e20 e10 e5 {"e100"=>1} e500 e200 e100 e50 e20 e10 e5 {"e20"=>2}

Mais je veux juste ça :

[{ "e100" => 1 },{ "e20" => 2 }]

Comment puis-je éliminer le reste ?

3voto

Stefan Points 23363

Vous pouvez obtenir le sortie en supprimant money << de votre return c'est-à-dire :

return {erg => anm}, (self-anm*value).atm

Ce qui donne :

puts 140.atm
{"e100"=>1}
{"e20"=>2}

Cependant, puts cache le fait que le résultat est en fait un tableau imbriqué avec une chaîne vide :

p 140.atm
[{"e100"=>1}, [{"e20"=>2}, ""]]

Pour résoudre ce problème, vous pouvez retourner nil si self est 0 :

return nil if self == 0

# or simply

return if self == 0

Et utiliser l'opérateur splat * sur le deuxième élément pour return pour "aplatir" la valeur de retour :

return {erg => anm}, *(self-anm*value).atm
#                    ^

Ce qui donne :

p 140.atm
[{"e100"=>1}, {"e20"=>2}]

Une autre option consiste à éviter la récursion et à collecter le résultat à l'intérieur de la boucle, par exemple :

def atm
  money =  %w[e500 e200 e100 e50 e20 e10 e5]

  i = self
  money.each_with_object([]) do |m, result|
    value = m.split('e').last.to_i
    anm, i = i.divmod(value)
    result << { m => anm } if anm > 0
  end
end

J'utilise divmod ici pour calculer le quotient et le reste (en fait le module) en une seule fois. Cela fonctionne comme suit :

140.divmod(500) #=> [0, 140]
140.divmod(200) #=> [0, 140]
140.divmod(100) #=> [1,  40]
 40.divmod( 50) #=> [0,  40]
 40.divmod( 20) #=> [2,   0]

Le premier élément du résultat détermine combien de fois les arguments "rentrent" dans le récepteur. Son deuxième élément est le reste qui devient également la nouvelle valeur de gauche.

Par exemple :

140.divmod(100) #=> [1,  40]
# means: 140 = 100 * 1 + 40

2voto

Cary Swoveland Points 6784

Objet à renvoyer

Vous trouverez peut-être plus pratique de retourner un hachage plutôt qu'un tableau de hachages. Par exemple,

645.atm
  #=> { 500=>1, 200=>0, 100=>1, 50=>0, 20=>2, 10=>0, 5=>1 }  
0.atm
  #=> { 500=>0, 200=>0, 100=>0, 50=>0, 20=>0, 10=>0, 5=>0 }  

sauf s'il n'y a aucun moyen de convertir le montant donné en différents montants des dénominations données, auquel cas nil est renvoyé :

646.atm
  #=> nil

Je suppose que, avant Integer#atm est appelé, il a été confirmé que le montant à modifier ( self ) est un nombre entier non négatif.

Integer#atm méthode

Nous pouvons écrire :

class Integer
  def atm
    denominations = [500, 200, 100, 50, 20, 10, 5]
    change = denominations.product([0]).to_h
    amount_to_change = self
    denominations.each do |d|
      change[d], amount_to_change = amount_to_change.divmod(d)
      return change if amount_to_change.zero?
    end
    nil
  end
end

Voir Tableau#produit , Tableau#to_h y Entier#divmod cette dernière étant une méthode très utile, mais sous-utilisée.

Essayez-le.

Essayons, mais d'abord je vais ajouter quelques puts pour illustrer les calculs intermédiaires.

class Integer
  def atm
    denominations = [500, 200, 100, 50, 20, 10, 5]
    change = denominations.product([0]).to_h
    puts "change=#{change}"
    amount_to_change = self
    puts "Initial amount_to_change=#{amount_to_change}"
    denominations.each do |d|
      change[d], amount_to_change = amount_to_change.divmod(d)
      puts "d=#{d}, change=#{change}, amount_to_change=#{amount_to_change}"
      return change if amount_to_change.zero?
    end
    nil
  end
end

645.atm
change={500=>0, 200=>0, 100=>0, 50=>0, 20=>0, 10=>0, 5=>0}
Initial amount_to_change=645
d=500, change={500=>1, 200=>0, 100=>0, 50=>0, 20=>0, 10=>0, 5=>0}, amount_to_change=145
d=200, change={500=>1, 200=>0, 100=>0, 50=>0, 20=>0, 10=>0, 5=>0}, amount_to_change=145
d=100, change={500=>1, 200=>0, 100=>1, 50=>0, 20=>0, 10=>0, 5=>0}, amount_to_change=45
d=50, change={500=>1, 200=>0, 100=>1, 50=>0, 20=>0, 10=>0, 5=>0}, amount_to_change=45
d=20, change={500=>1, 200=>0, 100=>1, 50=>0, 20=>2, 10=>0, 5=>0}, amount_to_change=5
d=10, change={500=>1, 200=>0, 100=>1, 50=>0, 20=>2, 10=>0, 5=>0}, amount_to_change=5
d=5, change={500=>1, 200=>0, 100=>1, 50=>0, 20=>2, 10=>0, 5=>1}, amount_to_change=0
  #=> {500=>1, 200=>0, 100=>1, 50=>0, 20=>2, 10=>0, 5=>1}

0.atm
change={500=>0, 200=>0, 100=>0, 50=>0, 20=>0, 10=>0, 5=>0}
Initial amount_to_change=0
  #=> {500=>0, 200=>0, 100=>0, 50=>0, 20=>0, 10=>0, 5=>0}

646.atm
change={500=>0, 200=>0, 100=>0, 50=>0, 20=>0, 10=>0, 5=>0}
Initial amount_to_change=646
d=500, change={500=>1, 200=>0, 100=>0, 50=>0, 20=>0, 10=>0, 5=>0}, amount_to_change=146
...
d=5, change={500=>1, 200=>0, 100=>1, 50=>0, 20=>2, 10=>0, 5=>1}, amount_to_change=1
  #=> nil

Rendre le code plus Semblable à du rubis en utilisant Enumerable#each_with_object

Vous constaterez que la méthode Enumerable#each_with_object est largement utilisé dans le code Ruby. Ici, il sera utilisé comme suit.

class Integer
  def atm
    denominations = [500, 200, 100, 50, 20, 10, 5]
    amount_to_change = self
    denominations.each_with_object(denominations.product([0]).to_h) do |d,change|
      change[d], amount_to_change = amount_to_change.divmod(d)
      return change if amount_to_change.zero?
    end
    nil
  end
end

Utiliser une valeur par défaut pour les clés de hachage

Un autre changement que vous pourriez envisager est d'utiliser Hash::new pour définir le hachage afin d'avoir un valeur par défaut de zéro :

change = Hash.new(0)
  #=> {}

Cela ne fait que provoquer change[k] pour revenir 0 lorsque le hachage n'a pas de clé k . Le hachage n'est pas modifié :

change[500]
  #=> 0
change
  #=> {}
change[500] = 1
change
  #=> {500=>1}

Nous pouvons maintenant modifier la méthode atm comme suit.

class Integer
  def atm
    denominations = [500, 200, 100, 50, 20, 10, 5]
    amount_to_change = self
    puts "Initial amount to change=#{amount_to_change}"
    denominations.each_with_object(Hash.new(0)) do |d,change|
      chg, amount_to_change = amount_to_change.divmod(d)
      change[d] = chg if chg > 0
      puts "d=#{d}, change=#{change}, amount_to_change=#{amount_to_change}"
      return change if amount_to_change.zero?
   end
   nil
  end
end

645.atm
Initial amount to change=645
d=500, change={500=>1}, amount_to_change=145
d=200, change={500=>1}, amount_to_change=145
d=100, change={500=>1, 100=>1}, amount_to_change=45
d=50, change={500=>1, 100=>1}, amount_to_change=45
d=20, change={500=>1, 100=>1, 20=>2}, amount_to_change=5
d=10, change={500=>1, 100=>1, 20=>2}, amount_to_change=5
d=5, change={500=>1, 100=>1, 20=>2, 5=>1}, amount_to_change=0
  #=> {500=>1, 100=>1, 20=>2, 5=>1}

Si nous calculons change = 645.atm et si nous avons besoin du nombre d'unités d'une dénomination donnée, il suffit d'écrire, par exemple,

change[500]
  #=> 1
change[50]
  #=> 0 (default value)

Nous devons toutefois garder à l'esprit que

change["cat"]
  #=> 0

Éviter de polluer la classe de base Integer

Singe Parcheando --L'ajout ou la modification de méthodes de base est généralement mal vu. Il est préférable d'écrire, par exemple,

def atm(amount_to_change)
  denominations = [500, 200, 100, 50, 20, 10, 5]
  denominations.each_with_object(Hash.new(0)) do |d,change|
    chg, amount_to_change = amount_to_change.divmod(d)
    change[d] = chg if chg > 0
    return change if amount_to_change.zero?
  end
  nil
end

Une autre option consiste à utiliser Raffinements .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X