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 .