Finden Sie den Herrn einer bestimmten Verbindung!

12

Herausforderung

Geben Sie anhand der Formel einer Chemikalie das Mr der Verbindung aus.

Gleichung

Jedem Element in der Verbindung folgt eine Nummer, die die Nummer des Atoms in der Verbindung angibt. Wenn es keine Zahl gibt, gibt es nur eines dieser Atome in der Verbindung.

Einige Beispiele sind:

  • Ethanol (C 2 H 6 O) wäre, C2H6Owenn es zwei Kohlenstoffatome, 6 Wasserstoffatome und 1 Sauerstoffatom gibt
  • Magnesiumhydroxid (MgO 2 H 2 ) wäre dort, MgO2H2wo es ein Magnesiumatom, zwei Sauerstoffatome und zwei Wasserstoffatome gibt.

Beachten Sie, dass Sie niemals mit Klammern umgehen müssen und jedes Element nur einmal in der Formel enthalten ist.

Während sich die meisten Leute wahrscheinlich an die Reihenfolge halten, in der sie sich am wohlsten fühlen, gibt es kein striktes Bestellsystem. Zum Beispiel kann Wasser entweder als H2Ooder angegeben werden OH2.

M r

Hinweis: Angenommen, die Formelmasse entspricht der Molekularmasse

Das Mr einer Verbindung, die Molekülmasse, ist die Summe der Atomgewichte der Atome im Molekül.

Die einzigen Elemente und ihre Atomgewichte bis 1 Dezimalstelle, die Sie unterstützen müssen (Wasserstoff bis Kalzium, Edelgase ausgenommen), sind wie folgt. Sie können auch hier gefunden werden

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

Sie sollten die Ausgabe immer mit einer Dezimalstelle versehen.

Zum Beispiel hat Ethanol ( C2H6O) ein Mr von, 46.0da es die Summe der Atomgewichte der Elemente in ihm ist:

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

Eingang

Eine einzelne Zeichenfolge im obigen Format. Sie können garantieren, dass die in der Gleichung enthaltenen Elemente tatsächliche Elementsymbole sind.

Es wird nicht garantiert, dass die angegebene Verbindung in der Realität existiert.

Ausgabe

Die Summe Mr der Verbindung auf 1 Dezimalstelle.

Regeln

Builtins, die auf Element- oder chemische Daten zugreifen, sind nicht erlaubt (sorry Mathematica)

Beispiele

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

Gewinnen

Kürzester Code in Bytes gewinnt.

Dieser Posten wurde mit Genehmigung von Caird Coinheringaahing angenommen . (Beitrag jetzt gelöscht)

Beta-Zerfall
quelle
Müssen wir quantifiers behandeln, wie zum Beispiel: 2H2O?
Mr. Xcoder
6
Für die Neugierigen ist dies die Mathematica-Lösung (53 Bytes):NumberForm[#&@@#~ChemicalData~"MolecularMass",{9,1}]&
JungHwan Min

Antworten:

6

Gelee , 63 Bytes

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

Ein monadischer Link, der eine Liste von Zeichen akzeptiert und eine Zahl zurückgibt.

Probieren Sie es online!

Wie?

ḟØ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
Jonathan Allan
quelle
Dies ist eine der längsten Gelee-Antworten, die ich je gesehen habe, aber es ist immer noch weniger als die Hälfte der Länge des Programms auf dem zweiten Platz, also gute Arbeit!
Gryphon
6

Python 3 ,  189 182  168 Bytes

-14 Bytes mit dem Hash aus Justin Mariners JavaScript (ES6) -Antwort .

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)])

Probieren Sie es online!


Unten ist die 182-Byte-Version, ich lasse die Erklärung für diese - das Obige ändert nur die Reihenfolge der Gewichte, verwendet int, um den Elementnamen von der Basis zu konvertieren 29, und verwendet verschiedene Dividenden, um den Bereich der ganzen Zahlen nach unten zu komprimieren - siehe Justin Mariners Antwort .

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)])

Eine unbenannte Funktion, die eine Zeichenfolge akzeptiert sund eine Zahl zurückgibt.

Probieren Sie es online!

Wie?

Verwendet einen regulären Ausdruck, um die Eingabe sin die Elemente und ihre Anzahl zu unterteilen. Dabei wird Folgendes verwendet:
re.findall("(\D[a-z]?)(\d*)",s)
\DStimmt genau mit einer Nicht-Ziffer [a-z]?überein und stimmt mit 0 oder 1 Kleinbuchstaben überein, wobei übereinstimmende Elemente zusammengefasst werden. \d*Stimmt mit 0 oder mehr Ziffern überein. Die Klammern unterteilen diese in zwei Gruppen und geben als solche findall("...",s)eine Liste mit Tupeln von Zeichenfolgen zurück [(element, number),...].

Die Zahl ist einfach zu extrahieren, ist das einzige , was zu behandeln , die eine leere Zeichenfolge Mittel 1, das mit einer logischen erreicht wird , orda Python Strings sind Falsey: int(n or 1).

Der Elementkette wird eine eindeutige Nummer gegeben, indem das Produkt der Ordinalzahlen des ersten und des letzten Zeichens genommen wird (normalerweise sind dies die gleichen, z. B. S oder C, aber wir müssen zwischen Cl, C, Ca und Na unterscheiden, damit wir nicht einfach eine verwenden können Charakter).

Diese Zahlen werden dann gehasht, um einen viel kleineren Bereich von [0,18] abzudecken, der durch Durchsuchen des Modulo-Raums gefunden wird, was zu führt %1135%98%19. Zum Beispiel "Cl"hat Ordnungszahlen 67und 108welche multiplizieren zu geben 7736, welche Modulo 1135ist 426, welche Modulo 98ist 34, welche Modulo 19ist 15; Diese Zahl wird verwendet, um eine Liste von ganzen Zahlen zu indizieren - der 15. (0-indizierte) Wert in der Liste
[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]
ist 35.5das Atomgewicht von Cl, das dann mit der Anzahl solcher Elemente multipliziert wird (wie oben gefunden).

Diese Produkte werden dann mit addiert sum(...).

Jonathan Allan
quelle
Sie sind ein Genie ... Hat mich um über 350 Bytes
übertroffen
4

PHP , 235 Bytes

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);

Probieren Sie es online!

Stattdessen 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])können Sie [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]mit der gleichen Bytezahl arbeiten

Jörg Hülsermann
quelle
3

JavaScript (ES6), 150 Byte

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

Inspiriert von Jonathan Allans Python-Antwort , in der er erklärte, jedem Element eine eindeutige Nummer zu geben und diese Nummern in einen kleineren Bereich zu bringen.

Die Elemente wurden zu eindeutigen Zahlen gemacht, indem sie als Basis 29 (0-9 und AS) interpretiert wurden. Dann stellte ich fest, dass %633%35%18sich die Werte auf den Bereich von beschränken, [0, 17]während die Eindeutigkeit erhalten bleibt.

Testschnipsel

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>

Justin Mariner
quelle
Oh, ich denke dein Weg würde mir auch ein paar Bytes sparen!
Jonathan Allan
2

Clojure, 198 194 Bytes

Update: besser forals 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))))

Original:

#(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]*)"%))

Ich frage mich, ob es eine kompaktere Möglichkeit gibt, die Nachschlagetabelle zu codieren.

NikoNyrh
quelle
2

Python 3 , 253 Bytes

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))

Probieren Sie es online!

ovs
quelle
1

Mathematica, 390 338 329 Bytes

9 Bytes gespart, weil ich gerade wach bin und die von mir beabsichtigte Verkürzung verwendet habe.

Version 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]&

Erläuterung: Ermitteln Sie die Position aller Großbuchstaben. Setzen Sie jeweils einen Punkt vor. Teilen Sie die Zeichenfolge an jedem Punkt. Führen Sie für diese Liste von Teilzeichenfolgen die folgenden Schritte aus: Teilen Sie die Liste anhand von Buchstaben und Ziffern auf. Für diejenigen, die durch Buchstaben getrennt sind, konvertieren Sie die Zeichenfolge in Zahlen. Für diejenigen, die durch Ziffern geteilt sind, ersetzen Sie jede Chemikalie durch ihr Molekulargewicht. Für alle mit einem Molekulargewicht und einer Atomzahl ersetzen Sie es durch das Produkt von ihnen. Sie finden die Summe.

Version 1:

Ich bin mir sicher, dass dies viele Golfplätze sein können (oder nur komplett umgeschrieben). Ich wollte nur herausfinden, wie es geht. (Wird am Morgen darüber nachdenken.)

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}&

Erläuterung: Teilen Sie zuerst die Zeichenfolge in Zeichen auf. Falten Sie dann das Array um und fügen Sie Kleinbuchstaben und Zahlen wieder zu ihrem Großbuchstaben hinzu. Fügen Sie am Ende einer Chemikalie eine 1 ohne Nummer hinzu. Führen Sie dann zwei Aufteilungen der Begriffe im Array durch - eine Aufteilung bei allen Zahlen und eine Aufteilung bei allen Buchstaben. Ersetzen Sie zuerst die Buchstaben durch ihre Molmassen und finden Sie dann das Skalarprodukt dieser beiden Listen.

Ian Miller
quelle
1

Python 3 - 408 Bytes

Dies ist hauptsächlich @ovs 'Lösung, da er es um über 120 Bytes reduziert hat ... Siehe die erste Lösung unten.

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)

Probieren Sie es online!

Python 3 - 550 548 535 Bytes (Zählung mit Einrückung verloren)

10 Bytes dank @cairdcoinheringaahing und 3 dank ovs gespeichert

Ich hatte das persönliche Ziel, kein Regex zu verwenden und es auf die unterhaltsame, altmodische Art und Weise zu tun ... Es stellte sich heraus, dass es 350 Bytes länger war als die Regex-Lösung, aber es verwendet nur die Standardbibliothek von 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)  

Probieren Sie es online!


Wenn irgendjemand bereit ist, Golf zu spielen (mit Einrückungskorrekturen und anderen Tricks ...), wird es zu 100% gut aufgenommen, und es scheint, als gäbe es einen besseren Weg, dies zu tun ...

Mr. Xcoder
quelle
Sie können for y in g: if str(y[0])==h[i][:h[i].index('-')]:x+=y[1]mitfor y in g:x+=y[1]*(str(y[0])==h[i][:h[i].index('-')])
Caird Coinheringaahing
@cairdcoinheringaahing ah, toll ... Aktualisierung, wenn ich Zugriff auf einen Computer habe
Mr. Xcoder
@ovs Vielen Dank! Haben Sie in der Antwort
gutgeschrieben
In Python können Sie anstelle eines Zeilenumbruchs ein Semikolon verwenden, um beim Einrücken Bytes zu sparen.
Pavel
@Phoenix nicht, wenn es if/for/whilein der nächsten Zeile eine gibt. Da dies in jeder eingerückten Zeile der Fall ist, können Sie dadurch keine Bytes speichern.
Ovs