化合物のモル質量


14

仕事

92(ウラン)以下の原子番号を持つ元素のみで作られた化合物を取り込み、化合物のモル質量をで出力するプログラムを作成しgrams/moleます。

ルールと制限

  • モル質量を直接計算する関数を使用することはできません。
  • プログラムは、オフラインマシンで実行できる必要があります。
  • 別のデータファイルを使用する場合があります。このファイルの内容を提供する必要があります。
  • スコアは、プログラムの長さ(バイト単位)と、使用することを選択した場合のデータファイルの長さ(バイト単位)です。
  • これはであるため、最低スコアが勝ちます。

入力

化合物を含む文字列。この文字列はSTDIN、読み通すか、引数として渡すか、変数に設定することができます(どれを指定してください)。以下はすべて有効な入力です。

  • CH2 (1つの炭素、2つの水素)
  • (CH2)8 (8炭素、16水素)
  • U (1ウラン)

プログラムは、埋め込み括弧(つまり((CH3)2N4)4)や、原子番号が92を超える要素を含む化合物に対して機能する必要はありません。上記の2つのケースのいずれかでプログラムが機能しない場合、そのInvalid formulaような場合に出力する必要があります-未定義の動作はありません。

出力

STDOUTの化合物のモル質量を変数に出力する必要がありますgrams/mole。元素の原子質量のリストは、ここ(Wikipedia)で入手できます。100個未満の原子を含む化合物(四捨五入)の場合、答えは小数点以下の精度である必要があります。

入力が無効な場合、Invalid formula出力する必要があります。

grams/mole(Wikipedia)の化合物のモル質量の計算に関する情報。

Input                   Output
H2O                     18.015
O                       15.999 (16 acceptable)
C6H2(NO2)3CH3           227.132
FOOF                    69.995
C6H12Op3                Invalid formula
Np                      237 (or Invalid formula)
((C)3)4                 144.132 (or Invalid formula)
CodeGolf                Invalid formula

1
「小数点まで」-分子の大きさは?質量は、U1000000質量より小数点を決定するために困難であるU2
ジョンドヴォルザーク

100個未満の原子を持つ分子の場合は小数点まで。これを質問文に追加しました。
es1024 14

私はまた13、原子質量が12.999
ジョンドヴォルザーク14

1
@ es1024のようには聞こえません。13、大丈夫ですが、12?
ラバーダック14

1
「あなたの答えは小数点以下の桁まで正確でなければなりません」それは、小数点以下1桁または最も近い整数を意味しますか?

回答:


5

バッシュ、 978 708 675 673 650 636 632 631 598 594

プログラム用に211バイト、データ用に382バイト。

入力はSTDINにあり、出力はSTDOUTにあります。WARNING:という名前のファイルを作成gしてa、それらが存在するならば、彼らは上書きされます!

zcat y>g 2>a
s=(`sed 's/[A-Z][a-z]*/& /g;q'<g`)
p=1.008
v=`sed 's/[0-9]\+/*&/g;s/(/+(0/g'`
r=(`tail -1 g`)
for n in {0..91};{
p=`bc<<<$p+${r[n]}`
v=${v//${s[n]}/+$p}
}
o=`bc<<<0$v 2>a`
echo ${o:-Invalid formula}

データファイル

これには、というデータが必要ですy。これは、このデータのzopfliで圧縮された形式です(末尾の改行はありません)。zopfliはgzip互換の圧縮アルゴリズムであり、標準のgzipツールで解凍できます。1024回の反復で実行されました(これはおそらく多すぎます)。その後、最後の8バイトが削除されました。

HHeLiBeBCNOFNeNaMgAlSiPSClKArCaScTiVCrMnFeNiCoCuZnGaGeAsSeBrKrRbSrYZrNbMoTcRuRhPdAgCdInSnSbITeXeCsBaLaCePrNdPmSmEuGdTbDyHoErTmYbLuHfTaWReOsIrPtAuHgTlPbBiPoAtRnFrRaAcPaThU
0 2.995 2.937 2.072 1.798 1.201 1.996 1.992 2.999 1.182 2.81 1.315 2.677 1.103 2.889 1.086 3.39 3.648 .850 .130 4.878 2.911 3.075 1.054 2.942 .907 2.848 .24 4.613 1.834 4.346 2.904 2.292 4.038 .944 3.894 1.670 2.152 1.286 2.318 1.682 3.054 2.04 3.07 1.836 3.514 1.448 4.543 2.407 3.892 3.050 5.144 .696 3.693 1.612 4.422 1.578 1.211 .792 3.334 .758 5.36 1.604 5.286 1.675 3.575 2.43 2.329 1.675 4.120 1.913 3.523 2.458 2.892 2.367 4.023 1.987 2.867 1.883 3.625 3.788 2.82 1.78 .02 1 12 1 3 1 4.036 1.002 5.991

base64は次のとおりyです(base64 -d元のファイルを再現するために使用):

H4sIAAAAAAACAwTB226DMAwA0G9LvEJQIbVi70LfHPBoJAiSaR729zsnBB2LVw/x0UWNMm1up4IE
+90ZCC1cvsCm2mkscEJ71l56dRept7ulTDY/Lebp5CW19MLVbbAOlSrlgfVH4fIyCihaXPGg49b6
lfPHXzhvxsecxxZ+Wb6TPq7B8O1a2HjH7Aue7p1qZ0ncgsKvz/8WxuRGoigGgfcfxYvA8r7kn9iA
ei6ohAt/+lzuihmD1PFnMrdIV0PeNfOczh3Ylrw8hnHaM6w1WC8V3X4hcYjOfbKlTyz0pewsP5nh
plOUK9mkPzkd4HLiCbktIGyQI5uaUvZzNBrwLhOf9hJij+Jo5WBf6mHLfh2OFqeaxOHbaGAZl5mL
h5UBI3Hlx99GX4llPumDjgw+NIee7uCaRbrZkzluIhJYi2E0ZU2gb5OnYBTSJQMRfv91irmCz4KK
B5Va5J7T7IGjHnR22PeAd+m3F3KW/voz4BMFPGNgxHE0Loq65M6+Pw==

md5sumはd392b0f5516033f2ae0985745f299efdです。

説明

ファイル内の数値は、相対原子質量の増分です(したがって、リチウムの相対原子質量はです1.008 + 0 + 2.995 + 2.937)。

このスクリプトは、化学式を+and *で算術式に変換し、各記号をその相対原子質量で置き換えてから、式をに渡すことで機能しbcます。数式に無効な記号が含まれている場合、bc構文エラーが発生し、STDOUTには何も出力されません。その場合、出力はInvalid formulaです。

STDINが空の場合、出力は0です。ネストされたブラケットがサポートされています。

zcat y>g 2>a # Unzip the file y and output result to the file g. Send standard error to file a (there will be an error because the last 8 bytes are missing)
s=(`sed 's/[A-Z][a-z]*/& /g;q'<g`)  # Read from g to sed; append a space after any capital letter optionally followed by a lowercase letter; exit at the end of the first line so the atomic masses are not processed in this way; parse result as space-separated array and save to variable $s
p=1.008 # In the upcoming loop, $p is the value obtained in the previous iteration
v=`sed 's/[0-9]\+/*&/g;s/(/+(0/g'` # Read from standard input to sed; prepend a * after any sequence of digits; replace ( with +(0; save to $v
r=(`tail -1 g`) # Get the last line of file g; parse as space-separated array; save to $r
for n in {0..91};{ # Loop once for each number from 0 to 91; set $n to the current number each iteration
p=`bc<<<$p+${r[n]}` # Concatenate $p, + and the next number from $r; send to bc and evaluate as arithmetic expression; save to $p (i.e. add the next increment from the file to $p)
v=${v//${s[n]}/+$p} # Replace every occurence of the current element symbol with + and $p (i.e. replace each symbol with a + and its relative atomic mass
} # end loop
o=`bc<<<0$v 2>a` # Prepend 0 to $v; send to bc and evaluate as arithmetic expression; redirect any errors on standard error to the file a; save result to $o
echo ${o:-Invalid formula} # If $o is empty (if there was a syntax error), output Invalid formula; otherwise output $o

C6H2(NO2)3CH3  #input
C*6H*2+(0NO*2)*3CH*3  #after line 3
+12.011*6+*1.008*2+(0+14.007+15.999*2)*3+12.011+1.008*3  #after the loop in lines 4-6
0+12.011*6+*1.008*2+(0+14.007+15.999*2)*3+12.011+1.008*3  #given to bc in line 7
227.132 #output as evaluated by bc

1
要素の質量の差を保存し、その場で計算することで、大幅に節約できます。最小値と最大値の差は-1.002と+6.993(Paのいずれかの側)です。原子番号順にではなく原子質量順に要素を並べ替えることにより、範囲は0〜5.991になります。周期表が考案されたとき、どちらの順序が良いかについて多くの議論がありました。(明らかに、化学の観点からは、原子番号の順序は優れていますが、それを決定するのに時間がかかりました。)
Level River St

@steveverrillコードを書くとき、私はすぐにそれを見ていきたいと思いました

@steveverrill完了、省は33文字程度であった

2

Perl-924

入力された数式に対して一連の正規表現置換操作を使用して、添え字付きの要素とグループを展開し、要素を原子量に置き換え、それを一連の加算に変換してから評価します。

$_=<>;chop;@g='H1008He4003Li6940Be9012B10810C12011N14007O15999F18998Ne20179Na22989Mg24305Al26981Si28085P30974S32060Cl35450Ar39948K39098Ca40078Sc44955Ti47867V50942Cr51996Mn54938Fe55845Co58933Ni58693Cu63546Zn65380Ga69723Ge72630As74922Se78960Br79904Kr83798Rb85468Sr87620Y88906Zr91224Nb92906Mo95960Tc98Ru101070Rh102906Pd106420Ag107868Cd112411In114818Sn118710Sb121760Te127600I126904Xe131293Cs132905Ba137327La138905Ce140116Pr140907Nd144242Pm145Sm150360Eu151964Gd157250Tb158925Dy162500Ho164930Er167259Tm168934Yb173054Lu174967Hf178490Ta180948W183840Re186207Os190230Ir192217Pt195084Au196967Hg200592Tl204380Pb207200Bi208980Po209At210Rn222Fr223Ra226Ac227Th232038Pa231036U238028'=~/(\D+)([\d\.]+)/g;for$b(0..91){$d=2*$b+1;$g[$d]=$g[$d]>999?$g[$d]/1000:$g[$d]}%h=@g;for$a('(\(((?>[^()]|(?1))*)\))(\d+)','()([A-Z][a-z]?)(\d+)'){for(;s/$a/$2x$3/e;){}}s/([A-Z][a-z]?)/($h{$1}||_).'+'/ge;if(/_/){print'Invalid formula';exit}$_.=0;print eval;

2

Mathematica 9-247 227

これは、原子質量を直接計算する関数を使用しているため、明らかに不正です(ただし、モル質量ではありません!)。

r=StringReplace;f[s_]:=Check[ToExpression@r[r[r[s,x:RegularExpression["[A-Z][a-z]*"]:>"ElementData[\""<>x<>"\",\"AtomicWeight\"]+"],x:DigitCharacter..:>"*"<>x<>"+"],{"+*"->"*","+"~~EndOfString->"","+)"->")"}],"Invalid formula"]

使用法:関数を呼び出す f数式を含む文字列ををと、出力が質量になります。

テスト:

f["H2O"]           (* => 18.0153 *)
f["O"]             (* => 15.9994 *)
f["C6H2(NO2)3CH3"] (* => 227.131 *)
f["FOOF"]          (* => 69.9956 *)
f["C6H12Op3"]      (* => Invalid formula *)
f["Np"]            (* => 237 *)
f["((C)3)4"]       (* => 144.128 *)
f["CodeGolf"]      (* => Invalid formula *)

Mathematica 10は生の数値ではなく単位付きの数値を出力するため、受け入れられない場合があります。


@MartinBüttnerありがたいことに、基本的にinitファイルから関数をコピーして、少しだけゴルフをしました。ゴルフは確かに改善される可能性があります。
ティロー14

2

Javascript、1002

入力はin q、出力はin aです。丸めの規則がわからないため、小数点以下3桁に切り捨てました(Wikipediaで数字が利用できない場合はそれ以下)。

H=1.008
He=4.002
Li=6.94
Be=9.012
B=10.812
C=12.011
N=14.007
O=15.999
F=18.998
Ne=20.179
Na=22.989
Mg=24.305
Al=26.981
Si=28.085
P=30.973
S=32.06
Cl=35.45
Ar=39.948
K=39.098
Ca=40.078
Sc=44.955
Ti=47.867
V=50.941
Cr=51.996
Mn=54.938
Fe=55.845
Co=58.933
Ni=58.693
Cu=63.546
Zn=65.38
Ga=69.723
Ge=72.630
As=74.921
Se=78.96
Br=79.904
Kr=83.798
Rb=85.467
Sr=87.62
Y=88.905
Zr=91.224
Nb=92.906
Mo=95.96
Tc=98
Ru=101.07
Rh=102.905
Pd=106.42
Ag=107.868
Cd=112.411
In=114.818
Sn=118.710
Sb=121.760
Te=127.60
I=126.904
Xe=131.293
Cs=132.905
Ba=137.327
La=138.905
Ce=140.116
Pr=140.907
Nd=144.242
Pm=145
Sm=150.36
Eu=151.964
Gd=157.25
Tb=158.925
Dy=162.500
Ho=164.930
Er=167.259
Tm=168.934
Yb=173.054
Lu=174.966
Hf=178.49
Ta=180.947
W=183.84
Re=186.207
Os=190.23
Ir=192.217
Pt=195.084
Au=196.966
Hg=200.592
Tl=204.38
Pb=207.2
Bi=208.980
Po=209
At=210
Rn=222
Fr=223
Ra=226
Ac=227
Th=232.038
Pa=231.035
U=238.028
try{a=eval(q.replace(/(\d+)/g,'*$1').replace(/(\w)(?=[A-Z\(])/g,'$1+'))}catch(e){a="Invalid formula"}

+1を使用して単純な変数を使用するというアイデアを...今、私は将来の恥のために過剰に複雑な答えを残すことができます
-edc65

入力は実際にはqにありますが、他のすべては正常に見えます。+1
es1024 14

末尾のゼロを削除することで、いくつかのバイトを節約できます:121.760 = 121.76
Fels 14

1

Javascript(E6)1231

入力を引数として、出力を返す関数として。精度:3桁の10進数

regexpを使用して、単純な算術式で化学式を変換し、和と積で置き換えます:

  • (+(
  • 「*」が付いた任意の数値シーケンス、次に数値シーケンス
  • 大文字の後に「+」が付いた文字が続き、対応する要素の原子質量(見つかった場合)

次に、式が評価され、値が返されます。エラーの場合、または値がNaN(またはゼロ)の場合、関数は「無効な式」を返します

今、私は他のすべての答えが同じメソッドを使用していることがわかります...まあここにjavascriptバージョンがあります

F=f=>{
  T={H:1.008,He:4.002,Li:6.94,Be:9.012,B:10.81,C:12.011
  ,N:14.007,O:15.999,F:18.998,Ne:20.179,Na:22.989,Mg:24.305
  ,Al:26.981,Si:28.085,P:30.973,S:32.06,Cl:35.45,Ar:39.948
  ,K:39.098,Ca:40.078,Sc:44.955,Ti:47.867,V:50.941,Cr:51.996,Mn:54.938
  ,Fe:55.845,Co:58.933,Ni:58.693,Cu:63.546,Zn:65.38,Ga:69.723,Ge:72.630
  ,As:74.921,Se:78.96,Br:79.904,Kr:83.798,Rb:85.467,Sr:87.62,Y:88.905,Zr:91.224
  ,Nb:92.906,Mo:95.96,Tc:98,Ru:101.07,Rh:102.905,Pd:106.42,Ag:107.868,Cd:112.411
  ,In:114.818,Sn:118.710,Sb:121.760,Te:127.60,I:126.904,Xe:131.293
  ,Cs:132.905,Ba:137.327,La:138.905,Ce:140.116,Pr:140.907,Nd:144.242,Pm:145
  ,Sm:150.36,Eu:151.964,Gd:157.25,Tb:158.925,Dy:162.500,Ho:164.930,Er:167.259
  ,Tm:168.934,Yb:173.054,Lu:174.966,Hf:178.49,Ta:180.947,W:183.84,Re:186.207
  ,Os:190.23,Ir:192.217,Pt:195.084,Au:196.966,Hg:200.592,Tl:204.38,Pb:207.2
  ,Bi:208.980,Po:209,At:210,Rn:222,Fr:223,Ra:226,Ac:227,Th:232.038,Pa:231.035
  ,U:238.028,Np:237,Pu:244,Am:243,Cm:247,Bk:247,Cf:251,Es:252,Fm:257,Md:258
  ,No:259,Lr:266,Rf:267,Db:268,Sg:269,Bh:270,Hs:269,Mt:278
  ,Ds:281,Rg:281,Cn:285,Uut:286,Fl:289,Uup:289,Lv:293,Uus:294,Uuo:294};
  e='Invalid formula';
  try{return eval(f.replace(/([A-Z][a-z]*)|(\d+)|(\()/g,(f,a,b,c)=>c?'+(':b?'*'+b:a='+'+T[a]))||e}
  catch(x){}return e
}

ほぼ同じ方法を使用しましたが、少なくとも1年前に関数を作成したため、少なくともコピーしませんでした。;)
ティロ14

1

PHP — 793(583 + 210)

同様の方法を使用しているprofessorfishの回答によって大いに距離を置いていますaが、次のコードで取得したファイルでは、シンボルとマスがgzip圧縮されています。

$symbolsList = ['H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mg', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U'];
$massesList = [1.008, 4.003, 6.94, 9.012, 10.81, 12.011, 14.007, 15.999, 18.998, 20.18, 22.99, 24.305, 26.982, 28.085, 30.974, 32.06, 35.45, 39.948, 39.098, 40.078, 44.956, 47.867, 50.942, 51.996, 54.938, 55.845, 58.933, 58.6934, 63.546, 65.38, 69.726, 72.630, 74.922, 78.96, 79.904, 83.798, 85.468, 87.62, 88.906, 91.224, 92.906, 95.96, 98, 101.07, 102.906, 106.42, 107.868, 112.411, 114.818, 118.710, 121.760, 127.60, 126.904, 131.293, 132.905, 137.327, 138.905, 140.116, 140.908, 144.242, 145, 150.36, 151.964, 157.25, 158.925, 162.5, 164.93, 167.259, 168.934, 173.054, 174.967, 178.49, 180.948, 183.84, 186.207, 190.23, 192.217, 195.084, 196.967, 200.592, 204.38, 207.2, 208.98, 209, 210, 222, 223, 226, 227, 232.038, 231.036, 238.029];

$fileArrayContent = [$symbolsList, $massesList];
$fileStringContent = json_encode($fileArrayContent);

$file = gzopen('a', 'w9');
gzwrite($file, $fileStringContent);
gzclose($file);

数式は$f変数に保存する必要があります。

$a=json_decode(gzfile('a')[0]);$r=@eval('return '.str_replace($a[0],$a[1],preg_replace(['#(?<=(?!\().)(\(|'.implode('|',$a[0]).')#','#\d+#'],['+${1}','*$0'],$f)).';');echo error_get_last()?'Invalid formula':$r;

以下は、コメントなしのバージョンです。

// Recover the data stored in the compressed file
$fileStringContent = gzfile('a')[0];
$fileArrayContent = json_decode($fileStringContent);
$symbolsList = $fileArrayContent[0];
$massesList = $fileArrayContent[1];

$formula = preg_replace('#(?<=(?!\().)(\(|'. implode('|', $symbolsList) .')#', '+${1}', $formula); // Add a "+" before each opening paranthesis and symbol not at the beginning of the string and not preceded by an opening paranthesis
$formula = preg_replace('#\d+#', '*$0', $formula); // Add a "*" before each number

$formula = str_replace($symbolsList, $massesList, $formula); // Replace each symbol with its corresponding mass

$result = @eval('return '. $formula .';'); // Evaluate the value without showing the errors
echo error_get_last() ? 'Invalid formula' : $result; // Print the value, or "Invalid formula" if there was an error

私は今1バイトずつあなたを

@professorfish本当に!それに、ファイルサイズを誤ってカウントしました。これは、以前に言ったサイズよりも大きいです。あなたは現在、はるかに勝者です、^^!
ブラックホール14

1

Scala、1077

私はあなたのすべてのソリューションを、動的に型付けされた言語で、evalまたは組み込みの原子質量関数のようなコプトアウトを使って見て、静的に型付けされた言語ソリューションを提供します:

object M{type S=String;type Z=(Int,S)
val d="H  *dHe JVLi inBe!!rB !5\"C !AiN !W!O !l3F \".*Ne\":_Na\"XUMg\"fUAl#%#Si#0iP #OOS #[&Cl$!,Ar$P|K $GxCa$RBSc%(7Ti%G5V %gwCr%s.Mn&4JFe&>)Co&^yNi&\\ECu'2\"Zn'ERGa'seGe(4^As(M#Se(x Br)$$Kr)MLRb)_5Sr)v,Y *%kZr*>LNb*PBMo*ppTc+(TRu+I4Rh+\\ePd,$,Ag,3RCd,cqIn,}LSn-HrSb-i>Te.IJI .B$Xe.peCs/#sBa/RwLa/ccCe/pXPr/y!Nd0>NPm0FTSm1!VEu12\\Gd1jrTb1|aDy2DdHo2^VEr2wATm3+0Yb3W Lu3k@Hf42nTa4L{W 4kfRe5&wOs5QdIr5fqPt6'BAu6;DHg6azTl7,8Pb7J8Bi7]2Po7]FAt7h$Rn9+bFr96@Ra9V8Ac9`tTh:8NPa:-mU :x4".grouped(5).map{s=>(s.take(2).trim,s(2)*8836+s(3)*94+s(4)-285792)}.toMap
def k(n:S):Z={val x=n.takeWhile(_.isDigit);(if(x=="")1 else x.toInt,n drop x.length)}
def o(m:S):Z={if(m(0)==40){val(i,s)=a(m.tail);if(s(0)!=41)???;val(j,t)=k(s.tail);(j*i,t)}else{val l=if(m.size>1&&m(1).isLower)2 else 1;val(i,s)=d(m.take(l))->m.drop(l);val(j,t)=k(s);(j*i,t)}}
def a(m:S)={var(r,s)=(m,0);do{val(y,z)=o(r);r=z;s+=y}while(r!=""&&r(0)!=41);s->r}
def main(q:Array[S]){println(try{val(m,s)=a(io.Source.stdin.getLines.next);if(s!="")???;m/1e3}catch{case _=>"Invalid formula"})}}

データの圧縮を検討する必要がありますが、とりあえず、ベース94に圧縮されていない原子質量を持たせてみましょう。


私を与えるmolarmass.scala:5: error: ';' expected but identifier found. def a(m:S)={var(r,s)=(m,0);do{val(y,z)=o(r);r=z;s+=y}while(r!=""&&r(0)!=41)s->r}
es1024

修繕。また、Scalaのパーサーは奇妙であることがわかりました。
カロルS 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.