与えられた化合物のミスターを見つけてください!


12

チャレンジ

化学式が与えられたら、化合物のM rを出力します。

方程式

化合物の各要素の後には、化合物の原子の数を示す数字が続きます。数字がない場合、化合物にはその原子が1つしかありません。

以下に例を示します。

  • エタノール(C 2 H 6 O)はC2H6O、2つの炭素原子、6つの水素原子、1つの酸素原子がある場所です。
  • 水酸化マグネシウム(MgO 2 H 2MgO2H2は、1つのマグネシウム原子、2つの酸素原子、2つの水素原子がある場所です。

角括弧を処理する必要は決してなく、各要素は式に一度だけ含まれることに注意してください。

ほとんどの人はおそらく最も快適だと感じる順序に固執するでしょうが、厳密な順序付けシステムはありません。例えば、水のいずれかとして与えられてもよいH2O、またはOH2

M r

注:ここでは、式質量が分子質量と同じであると仮定します

化合物のM r(分子量)は、分子内の原子の原子量の合計です。

サポートしなければならない唯一の元素とその小数点以下1桁までの原子量(希ガスを含まないカルシウムへの水素)は次のとおりです。こちらにもあります

H  - 1.0      Li - 6.9      Be - 9.0
B  - 10.8     C  - 12.0     N  - 14.0
O  - 16.0     F  - 19.0     Na - 23.0
Mg - 24.3     Al - 27.0     Si - 28.1
P  - 31.0     S  - 32.1     Cl - 35.5
K  - 39.1     Ca - 40.1

出力は常に小数点以下1桁にする必要があります。

たとえば、エタノール(C2H6O)のM r46.0、その中の元素の原子量の合計です。

12.0 + 12.0 + 1.0 + 1.0 + 1.0 + 1.0 + 1.0 + 1.0 + 16.0
(2*C + 6*H + 1*O)

入力

上記の形式の単一の文字列。方程式に含まれる要素が実際の要素シンボルになることを保証できます。

与えられた化合物は、実際に存在することが保証されていません。

出力

化合物の合計M r(小数点以下1桁まで)。

ルール

要素または化学データにアクセスするビルトインは許可されていません(ごめんなさいMathematica)

Input > Output
CaCO3 > 100.1
H2SO4 > 98.1
SF6 > 146.1
C100H202O53 > 2250.0

勝ち

バイト単位の最短コードが優先されます。

この投稿は、ケア共犯の許可を得て採択されました。(投稿は削除されました)


次のような量指定子を処理する必要があり2H2Oますか?
ミスターXcoder

6
好奇心のために、これは、Mathematicaの溶液(53バイト)である:NumberForm[#&@@#~ChemicalData~"MolecularMass",{9,1}]&
JungHwan分

回答:


6

ゼリー、63 バイト

ḟØDOP%⁽¡ṛị“ÇṚÆ’BH+“Ḳ"ɦṀ⁷6<s¡_-¦y⁼Ḟ¡¡FPɓ‘¤÷5
fØDVȯ1×Ç
Œs>œṗ⁸ḊÇ€S

文字のリストを受け入れ、数値を返す単項リンク。

オンラインでお試しください!

どうやって?

ḟØDOP%⁽¡ṛị“ÇṚÆ’BH+“Ḳ"ɦṀ⁷6<s¡_-¦y⁼Ḟ¡¡FPɓ‘¤÷5 - Link 1, Atomic weight: list of characters
                                            -                              e.g. "Cl23"
 ØD                                         - digit yield = "0123456789"
ḟ                                           - filter discard                      "Cl"
   O                                        - cast to ordinals                [67,108]
    P                                       - product                            7236
      ⁽¡ṛ                                   - base 250 literal = 1223
     %                                      - modulo                             1121
                                        ¤   - nilad followed by link(s) as a nilad:
          “ÇṚÆ’                             -   base 250 literal  = 983264
               B                            -   convert to binary = [    1,    1,     1,     1,   0,  0,  0,   0, 0,  0,  0, 0,     1,     1,     1, 0, 0,  0,  0,   0]
                H                           -   halve             = [  0.5,  0.5,   0.5,   0.5,   0,  0,  0,   0, 0,  0,  0, 0,   0.5,   0.5,   0.5, 0, 0,  0,  0,   0]
                  “Ḳ"ɦṀ⁷6<s¡_-¦y⁼Ḟ¡¡FPɓ‘    -   code-page indexes = [177  , 34  , 160  , 200  , 135, 54, 60, 115, 0, 95, 45, 5, 121  , 140  , 195  , 0, 0, 70, 80, 155]
                 +                          -   addition          = [177.5, 34.5, 160.5, 200.5, 135, 54, 60, 115, 0, 95, 45, 5, 121.5, 140.5, 195.5, 0, 0, 70, 80, 155]
         ị                                  - index into (1-indexed and modular)
                                            -    ...20 items so e.g. 1121%20=1 so 177.5
                                         ÷5 - divide by 5                          35.5

fØDVȯ1×Ç - Link 2: Total weight of multiple of atoms: list of characters   e.g. "Cl23"
 ØD      - digit yield = "0123456789"
f        - filter keep                                                            "23"
   V     - evaluate as Jelly code                                                  23
    ȯ1   - logical or with one (no digits yields an empty string which evaluates to zero)
       Ç - call last link (1) as a monad (get the atomic weight)                   35.5
      ×  - multiply                                                               816.5

Œs>œṗ⁸ḊÇ€S - Main link: list of characters                             e.g. "C24HCl23"
Œs         - swap case                                                      "c24hcL23"
  >        - greater than? (vectorises)                                      10011000
     ⁸     - chain's left argument                                          "C24HCl23"
   œṗ      - partition at truthy indexes                          ["","C24","H","Cl23"]
      Ḋ    - dequeue                                                 ["C24","H","Cl23"]
       Ç€  - call last link (2) as a monad for €ach                  [  288,  1,  816.5]
         S - sum                                                                 1105.5

これは、私が今まで見た中で最も長いジェリーの回答の1つですが、現在のプログラムの長さの2分の1以下であり、良い仕事です!
グリフォン

6

Pythonの3 189の182  168バイト

ジャスティンマリナーのJavaScript(ES6)answerのハッシュを使用して-14バイト。

import re
lambda s:sum([[9,35.5,39.1,24.3,28.1,14,16,31,40.1,23,32.1,10.8,12,27,6.9,19,0,1][int(a,29)%633%35%18]*int(n or 1)for a,n in re.findall("(\D[a-z]?)(\d*)",s)])

オンラインでお試しください!


以下は、182バイトのバージョンがあり、私はこの1つの説明を残しておきます-上記だけで、重みの順序を変更する用途intベースから要素名を変換するため29、およびダウン整数の範囲を圧縮するためにさまざまな配当を使用しています-参照ジャスティンをマリナーの答え

import re
lambda s:sum([[16,31,40.1,32.1,0,24.3,12,39.1,28.1,19,0,9,10.8,23,27,35.5,6.9,14,1][ord(a[0])*ord(a[-1])%1135%98%19]*int(n or 1)for a,n in re.findall("(\D[a-z]?)(\d*)",s)])

文字列を受け入れs、数値を返す名前のない関数。

オンラインでお試しください!

どうやって?

正規表現を使用して、入力、をs要素とそのカウントに分割します:
re.findall("(\D[a-z]?)(\d*)",s)
\D正確に1つの非数字に[a-z]?一致し、0または1の小文字に一致し、一致する要素を合わせます。\d*0以上の数字と一致します。括弧はこれらを2つのグループに分け、findall("...",s)文字列のタプルのリストを返します[(element, number),...]

数値は簡単に抽出できます。処理する必要があるのは、空の文字列が1を意味することだけです。これはor、Python文字列がfalsey であるため論理値で実現されますint(n or 1)

要素文字列には、最初と最後の文字の序数の積をとることによって一意の番号が与えられます(通常、これらは同じSまたはCなどですが、Cl、C、Ca、およびNaを区別する必要があるため、1つだけを使用することはできませんキャラクター)。

次に、これらの数値は、[0,18]の非常に小さい範囲をカバーするようにハッシュされ、モジュロ空間の検索により検出され、になり%1135%98%19ます。たとえば、"Cl"序数67とがあり108、それらは乗算して与え7736られ、モジュロ1135426、モジュロ9834、モジュロ1915; この番号は、整数のリストにインデックスを付けるために使用されます-リストの15番目の(0からインデックス付けされた)値は次のとおり
[16,31,40.1,32.1,0,24.3,12,39.1,28.1,19,0,9,10.8,23,27,35.5,6.9,14,1]
です。35.5、そのような要素(上記見られるような)の数を乗じてのClの原子量、。

これらの製品は、を使用して一緒に追加されsum(...)ます。


あなたは天才です... 350バイト以上も私をgしみません
Xcoder氏

4

PHP、235バイト

preg_match_all("#([A-Z][a-z]?)(\d*)#",$argn,$m);foreach($m[1]as$v)$s+=array_combine([H,Li,Be,B,C,N,O,F,Na,Mg,Al,Si,P,S,Cl,K,Ca],[1,6.9,9,10.8,12,14,16,19,23,24.3,27,28.1,31,32.1,35.5,39.1,40.1])[$v]*($m[2][+$k++]?:1);printf("%.1f",$s);

オンラインでお試しください!

代わりにarray_combine([H,Li,Be,B,C,N,O,F,Na,Mg,Al,Si,P,S,Cl,K,Ca],[1,6.9,9,10.8,12,14,16,19,23,24.3,27,28.1,31,32.1,35.5,39.1,40.1])使用できます[H=>1,Li=>6.9,Be=>9,B=>10.8,C=>12,N=>14,O=>16,F=>19,Na=>23,Mg=>24.3,Al=>27,Si=>28.1,P=>31,S=>32.1,Cl=>35.5,K=>39.1,Ca=>40.1]、同じバイト数で


3

JavaScript(ES6)、150バイト

c=>c.replace(/(\D[a-z]?)(\d+)?/g,(_,e,n=1)=>s+=[9,35.5,39.1,24.3,28.1,14,16,31,40.1,23,32.1,10.8,12,27,6.9,19,0,1][parseInt(e,29)%633%35%18]*n,s=0)&&s

に触発さ Jonathan AllanのPythonの回答に、彼は各要素に一意の番号を与え、それらの番号をより小さな範囲にハッシュすることを説明しました。

要素は、それらをbase-29(0-9およびAS)として解釈することにより、一意の番号になりました。それから私はそれを見つけました%633%35%18、値を次の範囲に絞り込む[0, 17]一意性を維持しながら。

テストスニペット

f=
c=>c.replace(/(\D[a-z]?)(\d+)?/g,(_,e,n=1)=>s+=[9,35.5,39.1,24.3,28.1,14,16,31,40.1,23,32.1,10.8,12,27,6.9,19,0,1][parseInt(e,29)%633%35%18]*n,s=0)&&s
Input: <input oninput="O.value=f(this.value)"><br>
Result: <input id="O" disabled>


ああ、あなたの方法は私にも数バイトを節約すると思います!
ジョナサンアラン

2

Clojure、 198 194バイト

アップデート:より良いforよりreduce

#(apply +(for[[_ e n](re-seq #"([A-Z][a-z]?)([0-9]*)"%)](*(if(=""n)1(Integer. n))({"H"1"B"10.8"O"16"Mg"24.3"P"31"K"39.1"Li"6.9"C"12"F"19"Al"2"S"32.1"Ca"40.1"Be"9"N"14"Na"23"Si"28.1"Cl"35.5}e))))

元の:

#(reduce(fn[r[_ e n]](+(*(if(=""n)1(Integer. n))({"H"1"B"10.8"O"16"Mg"24.3"P"31"K"39.1"Li"6.9"C"12"F"19"Al"2"S"32.1"Ca"40.1"Be"9"N"14"Na"23"Si"28.1"Cl"35.5}e))r))0(re-seq #"([A-Z][a-z]?)([0-9]*)"%))

ルックアップテーブルをエンコードするよりコンパクトな方法があるかどうか疑問に思っています。


2

Python 3、253バイト

def m(f,j=0):
 b=j+1
 while'`'<f[b:]<'{':b+=1
 c=b
 while'.'<f[c:]<':':c+=1
 return[6.9,9,23,40.1,24.3,27,28.1,35.5,31,32.1,39.1,1,10.8,12,14,16,19]['Li Be Na Ca Mg Al Si Cl P S K H B C N O F'.split().index(f[j:b])]*int(f[b:c]or 1)+(f[c:]>' 'and m(f,c))

オンラインでお試しください!


1

Mathematica、390 338 329 Bytes

実際に目を覚まし、実際に意図した短縮を使用していたため、9バイトを節約しました。

バージョン2.1:

S=StringSplit;Total[Flatten@{ToExpression@S[#,LetterCharacter],S[#,DigitCharacter]}&/@S[StringInsert[#,".",First/@StringPosition[#,x_/;UpperCaseQ[x]]],"."]/.{"H"->1,"Li"->3,"Be"->9,"B"->10.8,"C"->12,"N"->14,"O"->16,"F"->19,"Na"->23,"Mg"->24.3,"Al"->27,"Si"->28.1,"P"->31,"S"->32.1,"Cl"->35.5,"K"->39.1,"Ca"->40.1}/.{a_,b_}->a*b]&

説明:すべての大文字の位置を見つけます。それぞれの前にドットを置きます。各ドットで文字列を分割します。この部分文字列のリストでは、文字に基づいて次のように分割し、数字に基づいて分割します。文字で分割されたものについては、文字列を数字に変換します。数字で区切られたものについては、各化学物質をその分子量に置き換えます。分子量と原子数のあるものについては、それらの積に置き換えてください。それらは合計を見つけます。

バージョン1:

私はこれがゴルフのロット(または完全に書き直された)であると確信しています。私はそれを行う方法を理解したかっただけです。(午前中にそれを反映します。)

F=Flatten;d=DigitCharacter;S=StringSplit;Total@Apply[Times,#,2]&@(Transpose[{F@S[#,d],ToExpression@F@S[#,LetterCharacter]}]&@(#<>If[StringEndsQ[#,d],"","1"]&/@Fold[If[UpperCaseQ[#2],Append[#,#2],F@{Drop[#,-1],Last[#]<>#2}]&,{},StringPartition[#,1]]))/.{"H"->1,"Li"->3,"Be"->9,"B"->10.8,"C"->12,"N"->14,"O"->16,"F"->19,"Na"->23,"Mg"->24.3,"Al"->27,"Si"->28.1,"P"->31,"S"->32.1,"Cl"->35.5,"K"->39.1,"Ca"->40.1}&

説明:最初に、ストリングを文字に分割します。次に、小文字と数字を結合して大文字に戻す配列を折りたたみます。次に、最後に数字のない化学物質に1を追加します。次に、配列内の用語の2つの分割を行います。1つはすべての数字で分割し、もう1つはすべての文字で分割します。最初に、文字をモル質量に置き換えてから、これら2つのリストのドット積を見つけます。


1

Python 3-408バイト

これは主に@ovsのソリューションです。彼はそれを120バイト以上も減らしたからです...以下の最初のソリューションをご覧ください。

e='Li Be Na Ca Mg Al Si Cl P S K H B C N O F'.split()
f,g=input(),[]
x=r=0
for i in e:
 if i in f:g+=[(r,eval('6.9 9 23 40.1 24.3 27 28.1 35.5 31 32.1 39.1 1 10.8 12 14 16 19'.split()[e.index(i)]))];f=f.replace(i,' %d- '%r);r+=1
h=f.split()
for c,d in zip(h,h[1:]):
 s=c.find('-')
 if-1<s:
  if'-'in d:
   for y in g:x+=y[1]*(str(y[0])==c[:s])
  else:
   for y in g:x+=y[1]*int(d)*(str(y[0])==c[:s])
print(x)

オンラインでお試しください!

Python 3-550 548 535バイト(インデントでカウントを失いました)

@cairdcoinheringaahingのおかげで10バイト、ovsのおかげで3 バイト節約

私は正規表現を一切使用せず、楽しく、昔ながらの方法でそれを行うという個人的な目標がありました...正規表現ソリューションよりも350バイト長いことが判明しましたが、Pythonの標準ライブラリのみを使用しています...

a='Li6.9 Be9. Na23. Ca40.1 Mg24.3 Al27. Si28.1 Cl35.5 P-31. S-32.1 K-39.1 H-1. B-10.8 C-12. N-14. O-16. F-19.'.split()
e,m,f,g,r=[x[:1+(x[1]>'-')]for x in a],[x[2:]for x in a],input(),[],0
for i in e:
 if i in f:g.append((r,float(m[e.index(i)])));f=f.replace(i,' '+str(r)+'- ');r+=1;
h,x=f.split(),0
for i in range(len(h)):
 if '-'in h[i]:
    if '-'in h[i+1]:
     for y in g:x+=y[1]*(str(y[0])==h[i][:h[i].index('-')])
    else:
        for y in g:
         if str(y[0])==h[i][:h[i].index('-')]:x+=(y[1])*int(h[i+1])
 else:1
print(x)  

オンラインでお試しください!


誰かがそれを下に喜んで(インデントの修正やその他のトリックを使って...)、それを行うためのより良い方法があるように感じて、それは100%好評です...


あなたは置き換えることができfor y in g: if str(y[0])==h[i][:h[i].index('-')]:x+=y[1]for y in g:x+=y[1]*(str(y[0])==h[i][:h[i].index('-')])
coinheringaahing caird

偉大な、ああ@cairdcoinheringaahing ...私はコンピュータへのアクセスを持っている場合更新
氏Xcoder

@ovsどうもありがとう!答えにあなたのクレジット
Xcoder氏

Pythonでは、改行の代わりにセミコロンを使用できます。これにより、インデント時にバイトを節約できます。
パベル

@Phoenixではなくif/for/while、次の行にある場合。これはすべてのインデントされた行に当てはまるので、これによってバイトを節約することはできません。
ovs
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.