Re: subroutine help
by NetWallah (Canon) on Nov 29, 2012 at 06:53 UTC
|
Your code does not compile, and your problem description is wrong.
Your problems have to do with converting between the returned array, and the scalar
$weight you assign it to.
Please search this site for responses to Your and your collegues VERY SIMILAR questions over the last few days, and avoid duplicate questions.
"By three methods we may learn wisdom: First, by reflection, which is noblest; Second, by imitation, which is easiest; and third by experience, which is the bitterest."
-Confucius
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
Sorry I will make sure to look next time
| [reply] [Watch: Dir/Any] |
Re: subroutine help
by CountZero (Bishop) on Nov 29, 2012 at 07:16 UTC
|
When you print an array, like print @array; then all elements of the array are printed next to each other without any separation.On the other hand if you print the array like print "@array"; then the array is first interpolated, i.e. the elements are joined by whatever is in $" (usually a space).
CountZero A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James My blog: Imperial Deltronics
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
without any separation
Well, the members of the list are separated by $, which is empty by default.
| [reply] [Watch: Dir/Any] [d/l] |
Re: subroutine help
by frozenwithjoy (Priest) on Nov 29, 2012 at 07:05 UTC
|
#!/usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use Data::Printer;
print "Enter a chemical formula: ";
chomp( my $form = <> );
my %weight = $form =~ /[A-Z][a-z]?|\d+/ig;
p %weight;
__END__
Enter a chemical formula: C12H22O11
{
C 12,
H 22,
O 11
}
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Sorry I think my kindle modified it and removed the ;
| [reply] [Watch: Dir/Any] |
|
Oh, those pesky kindles! (I wonder whatever happened to the 'dog ate my semi-colon' excuse?)
| [reply] [Watch: Dir/Any] |
Re: subroutine help
by space_monk (Chaplain) on Nov 29, 2012 at 07:37 UTC
|
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.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
'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
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
Don't forget your units: g/mol! :P
| [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] |
|
|
Thank you so much this actually explains a lot I was heading the wrong way thanks =)
| [reply] [Watch: Dir/Any] |
Re: subroutine help
by Anonymous Monk on Nov 30, 2012 at 20:28 UTC
|
The arguments to a subroutine are ... a list. If you "pass an array," Perl might flatten that array into a list of individual arguments. What you really want to do is to pass one argument to the subroutine, consisting of a reference to that array; an "arrayref." A reference (to anything...) is always "one thing." Be explicit about how you say this sort of thing to Perl, because Perl does try to "do what I mean (DWIM)" and is sometimes wrong. Also be sure to say use strict; use warnings; at the top of your module so that problems which might otherwise "helpfully" be ignored will be told to you. | [reply] [Watch: Dir/Any] |