2010-07-22 18 views
0

J'essaie de parcourir un tableau, @chem_species = ["H2", "S", "O4"] et de multiplier une constante fois la quantité de constantes présentes: H = 1.01 * 2, S = 32.1 * 1 et ainsi de suite. Les constantes sont bien sûr définies dans la classe, avant la méthode de l'instance.impossible de convertir un tableau en entier

Le code que je l'ai construit pour faire cela ne fonctionne pas:

def fw 
x = @chem_species.map { |chem| chem.scan(/[A-Z]/)} 
y = @chem_species.map { |chem| chem.scan({/\d+/)} 
@mm = x[0] * y[0] 
end 

rendements ->TypeError: can't convert Array into Integer

Toutes les suggestions sur la façon de mieux le code cela? Merci pour votre perspicacité à l'avance.

Répondre

3

Que diriez-vous de le faire en un seul scan de carte &? La méthode String#scan renvoie toujours un tableau des chaînes correspondantes. Regardez ceci:

irb> "H2".scan /[A-Z]+|\d+/i 
    => ["H", "2"] 

Il suffit donc de l'appliquer à tous vos @chem_species en utilisant map:

irb> @chem_species.map! { |chem| chem.scan /[A-Z]+|\d+/i } 
    => [["H", "2"], ["S"], ["O", "4"]] 

OK, maintenant Carte sur @chem_species, la conversion de chaque symbole de l'élément à la valeur de sa constante, et chacun coefficient à un nombre entier:

irb> H = 1.01 
irb> S = 32.01 
irb> O = 15.99 
irb> @chem_species.map { |(elem, coeff)| self.class.const_get(elem) * (coeff || 1).to_i } 
    => [2.02, 32.01, 63.96] 

Il y a vos masses molaires! Par ailleurs, je vous suggère de rechercher les masses molaires dans une seule constante de hachage au lieu de plusieurs constantes pour chaque élément.Comme ceci:

MASSES = { :H => 1.01, :S => 32.01, :O => 15.99 } 

Alors que la dernière carte irait comme:

@chem_species.map { |(elem, coeff)| MASSES[elem.to_sym] * (coeff || 1).to_i } 
+0

Très belle réponse. – theIV

+0

mon dieu tu n'as que 18 ans. Tu devrais penser à la science computationnelle au collège. C'était une excellente réponse. –

0

Vous avez une erreur de syntaxe dans votre code: Peut-être qu'il devrait être:

def fw 
x = @chem_species.map { |chem| chem.scan(/[A-Z]/)} 
y = @chem_species.map { |chem| chem.scan(/\d+/)} 
@mm = x[0] * y[0] 
end 
+1

Je pense que vous voulez dire "erreur de syntaxe". – AShelly

+0

@AShelly: oui. Je vous remercie. – txwikinger

+0

C'était une erreur de traduction entre mon ordinateur portable et mon ordinateur de bureau. Merci d'avoir attrapé cela, je l'ai corrigé ci-dessus mais ce n'est pas la source de l'erreur dans ruby. –

0

Avez-vous regardé la sortie de @chem_species.map { |chem| chem.scan(/[A-Z]/)} (ou le second d'ailleurs)? Cela vous donne une panoplie de tableaux, donc si vous vouliez vraiment suivre cette approche, vous deviez faire x[0][0].

Au lieu de map ping, faire each

@chem_species.each { |c| c.scan(/[A-Z]/) } 

Edit: viens juste de réaliser que cela ne fonctionne pas du tout ce que je pensais qu'il a fait, mes excuses sur une réponse stupide : P

0

Voici un moyen de multiplier les valeurs une fois que vous les avez. L'opérateur * ne fonctionnera pas sur les tableaux.

x = [ 4, 5, 6 ] 
y = [ 7, 8, 9 ] 
res = [] 
x.zip(y) { |a,b| res.push(a*b) } 
res.inject(0) { |sum, v| sum += v} 
# sum => 122 

Ou, coupant l'homme du milieu:

x = [ 4, 5, 6 ] 
y = [ 7, 8, 9 ] 
res = 0 
x.zip(y) { |a,b| res += (a*b) } 
# res => 122 
0

(one-liners alerte, hors-sujet d'alerte)

vous pouvez analyser directement la formule:

"H2SO4".scan(/([A-Z][a-z]*)(\d*)/) 
# -> [["H", "2"], ["S", ""], ["O", "4"]] 

calculer les sommes partielles:

aw = { 'H' => 1.01, 'S' => 32.07, 'O' => 16.00 } 
"H2SO4".scan(/([A-Z][a-z]*)(\d*)/).collect{|e,x| aw[e] * (x==""?1:x).to_i} 
# -> [2.02, 32.07, 64.0] 

somme totale:

"H2SO4".scan(/([A-Z][a-z]*)(\d*)/).collect{|e,x| aw[e] * (x==""?1:x).to_i}.inject{|s,x| s+x} 
# -> 98.09