Beefy Boxes and Bandwidth Generously Provided by pair Networks Bob
There's more than one way to do things

Re: subroutine help

by space_monk (Chaplain)
on Nov 29, 2012 at 07:37 UTC ( #1006179=note: print w/ replies, xml ) Need Help??

in reply to subroutine help

I'm sure it's been done before in the other answers, and maybe even more efficiently, but this is what I think you're trying to get to:

#!/bin/perl #if your program doesn't begin with this, you deserve to fail... use strict; # Data::Dumper not used in example, # but you always need it when you expand the module :-) use Data::Dumper; # you can either hardcode all atomic weights in ... # ..or read them from a data file/ database my %weights = ( 'C' => 12.0, 'O' => 16.0, 'Co' => 58.933195, 'H' => 1.008 ); my @test = ( 'C12H22O11' ); for my $form (@test) { my @array = $form =~ /[A-Z][a-z]*\d*/ig; my $weight = getweight(@array); print "Weight of @array : $weight\n"; } sub getweight { my @atoms =@_; my $weight = 0.0; for my $element (@atoms) { if ($element =~ /([A-Z][a-z]*)(\d*)/) { my $eweight = $weights{$1}; my $mult = $2 || 1; $weight += ($eweight*$mult); print STDERR "Adding $1 ($eweight)* $mult\n"; } } print STDERR "Molecule: @atoms\n"; return $weight; }

Feel free to modify for your purposes and correct naming,read atomic weights from a file etc.

Output from above program:

Adding C (12)* 12 Adding H (1.008)* 22 Adding O (16)* 11 Molecule: C12 H22 O11 Weight of C12 H22 O11 : 342.176
Updated to reflect the fact that some transuranic elements have 3 letter identifiers, not just two. :-)

Also updated to reflect suggestions by Kenosis and others below....

Whilst adequate for the indicated input, the method of parsing and atomic weight calculation is a little lightweight and basic, and doesn't handle more complex molecules, so consider using Chemistry::Mol or a similar package if you want to get round the flaws that have been indicated below....

A Monk aims to give answers to those who have none, and to learn from those who know more.

Comment on Re: subroutine help
Select or Download Code
Re^2: subroutine help
by frozenwithjoy (Curate) on Nov 29, 2012 at 07:51 UTC
    Don't forget your units: g/mol! :P
      Its 30 years since I did Chemistry 'A' grateful I remembered this much. :-)
      A Monk aims to give answers to those who have none, and to learn from those who know more.
        I was impressed with (and had to google) 'transuranic elements'! (And I was teasing, of course.)
Re^2: subroutine help
by perlguru22 (Acolyte) on Nov 29, 2012 at 08:10 UTC
    Thank you so much this actually explains a lot I was heading the wrong way thanks =)
Re^2: subroutine help
by Kenosis (Priest) on Nov 29, 2012 at 08:22 UTC

    Consider the following minor modifications:

    'Co' => 58.933195 my @array = $form =~ /[A-Z][a-z]*\d*/g; if ($element =~ /([A-Z][a-z]*)(\d*)/) { my $mult = $2 || 1; $weight += ($eweight*$mult); print STDERR "Adding $1 ($eweight)* $mult\n";

    Run on CoCO2:

    Adding Co (58.933195)* 1 Adding C (12)* 1 Adding O (16)* 2 Molecule: Co C O2 Weight of Co C O2 : 102.933195
Re^2: subroutine help
by tobyink (Abbot) on Nov 29, 2012 at 09:05 UTC

    A few evil examples:

    • Ca(OH)2
    • CH3[CH2]5CH3
    • CH3[CH2]nCH3 - not really calculable, but should be parsable
    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
      Yes, alright my solution is lightweight, only getting the second of your examples right, lets use Chemistry::Mol to get it right properly :-)
      A Monk aims to give answers to those who have none, and to learn from those who know more.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1006179]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (9)
As of 2014-04-19 05:12 GMT
Find Nodes?
    Voting Booth?

    April first is:

    Results (478 votes), past polls